From a31cf4c7b7340ab004b48160f4807032946ffc5c Mon Sep 17 00:00:00 2001 From: Oleg Shilov Date: Mon, 15 Apr 2024 22:49:00 +0700 Subject: [PATCH 01/13] wip --- apps/shell/src/app/error.tsx | 24 +- apps/shell/src/app/global-error.tsx | 27 +- apps/shell/src/app/global.css | 6 - .../src/app/governance/proposal/new/page.tsx | 35 + .../src/components/submit-proposal-form.tsx | 439 +++++++++++ .../submit-proposal-su-form-keplr.tsx | 554 ++++++++++++++ libs/data-access/cosmos/jest.config.ts | 2 +- libs/data-access/cosmos/src/lib/chains.ts | 5 +- libs/data-access/falconer/jest.config.ts | 2 +- libs/shell/authz/project.json | 40 +- libs/shell/faucet/project.json | 40 +- libs/shell/governance/project.json | 40 +- libs/shell/main/project.json | 40 +- libs/shell/shared/package.json | 5 +- libs/shell/shared/project.json | 42 +- .../use-authz-actions/use-authz-actions.tsx | 4 +- .../use-proposal-actions.ts | 712 +++++++++++++++++- .../shared/src/providers/wagmi-provider.tsx | 29 +- .../shared/src/providers/wallet-provider.tsx | 5 +- libs/shell/staking/project.json | 40 +- libs/shell/ui-kit/src/index.ts | 1 - 21 files changed, 1928 insertions(+), 164 deletions(-) create mode 100644 apps/shell/src/app/governance/proposal/new/page.tsx create mode 100644 apps/shell/src/components/submit-proposal-form.tsx create mode 100644 apps/shell/src/components/submit-proposal-su-form-keplr.tsx diff --git a/apps/shell/src/app/error.tsx b/apps/shell/src/app/error.tsx index f185176ce..f15146e8e 100644 --- a/apps/shell/src/app/error.tsx +++ b/apps/shell/src/app/error.tsx @@ -1,6 +1,7 @@ 'use client'; import { useEffect } from 'react'; import * as Sentry from '@sentry/nextjs'; +import { Button, Container, Heading } from '@haqq/shell-ui-kit'; export default function ErrorPage({ error, @@ -15,15 +16,18 @@ export default function ErrorPage({ }, [error]); return ( -
-

Something went wrong!

- -
+ +
+ Something went wrong! + + +
+
); } diff --git a/apps/shell/src/app/global-error.tsx b/apps/shell/src/app/global-error.tsx index ddd0f00dd..46083527f 100644 --- a/apps/shell/src/app/global-error.tsx +++ b/apps/shell/src/app/global-error.tsx @@ -2,6 +2,7 @@ import { useEffect } from 'react'; import * as Sentry from '@sentry/nextjs'; import NextError from 'next/error'; +import { Button, Heading } from '@haqq/shell-ui-kit'; export default function GlobalError({ error, @@ -17,17 +18,21 @@ export default function GlobalError({ return ( -

Something went wrong!

- {/* This is the default Next.js error component but it doesn't allow omitting the statusCode property yet. */} - {/* eslint-disable-next-line @typescript-eslint/no-explicit-any */} - - +
+ Something went wrong! + + + + {/* This is the default Next.js error component but it doesn't allow omitting the statusCode property yet. */} + {/* eslint-disable-next-line @typescript-eslint/no-explicit-any */} + +
); diff --git a/apps/shell/src/app/global.css b/apps/shell/src/app/global.css index 2e0650451..7d04e0107 100644 --- a/apps/shell/src/app/global.css +++ b/apps/shell/src/app/global.css @@ -38,10 +38,4 @@ body { body { @apply bg-haqq-black font-guise text-white will-change-scroll; - - /* background-image: url(/sunrise.jpg); - background-position: top center; - background-repeat: no-repeat; - background-size: contain; - background-attachment: fixed; */ } diff --git a/apps/shell/src/app/governance/proposal/new/page.tsx b/apps/shell/src/app/governance/proposal/new/page.tsx new file mode 100644 index 000000000..945dd8bc4 --- /dev/null +++ b/apps/shell/src/app/governance/proposal/new/page.tsx @@ -0,0 +1,35 @@ +import { + HydrationBoundary, + QueryClient, + dehydrate, +} from '@tanstack/react-query'; +import { Container } from '@haqq/shell-ui-kit'; +import { + CreateTextProposalForm, + CreateUpgradeProposalForm, +} from '../../../../components/submit-proposal-form'; +// import { CreateProposalFormKeplr } from '../../../../components/submit-proposal-su-form-keplr'; + +export default async function CreateProposal() { + const queryClient = new QueryClient(); + + const dehydratedState = dehydrate(queryClient); + + return ( + +
+
+ +
+ Submit proposal +
+
+
+ + + + {/* */} +
+
+ ); +} diff --git a/apps/shell/src/components/submit-proposal-form.tsx b/apps/shell/src/components/submit-proposal-form.tsx new file mode 100644 index 000000000..cc1559392 --- /dev/null +++ b/apps/shell/src/components/submit-proposal-form.tsx @@ -0,0 +1,439 @@ +'use client'; +import { useCallback } from 'react'; +import { yupResolver } from '@hookform/resolvers/yup'; +import clsx from 'clsx'; +import Link from 'next/link'; +import { useForm, SubmitHandler } from 'react-hook-form'; +import { useNetwork } from 'wagmi'; +import * as Yup from 'yup'; +import { getChainParams } from '@haqq/data-access-cosmos'; +import { + CreateTextProposalForm, + getFormattedAddress, + useProposalActions, + useSupportedChains, + useToast, +} from '@haqq/shell-shared'; +import { + Button, + Container, + Heading, + LinkIcon, + ToastError, + ToastLoading, + ToastSuccess, +} from '@haqq/shell-ui-kit'; +import { FormInputError } from './submit-proposal-su-form-keplr'; + +const inputClassnames = clsx( + 'inline-block w-full rounded-[6px] border border-white/20 bg-transparent px-[16px] py-[12px] text-[14px] leading-[22px] text-white placeholder-white/25 outline-none', + 'transition-colors duration-150 ease-in will-change-[color,background]', + 'focus:border-white/30 focus:bg-transparent focus:text-white', + 'hover:border-white/10', +); + +const submitTextProposalSchema = Yup.object({ + title: Yup.string().required('Title is required'), + description: Yup.string().required('Description is required'), + initialDeposit: Yup.number() + .min(0, 'Deposit cannot be negative') + .required('Deposit is required'), +}).required(); + +const submitUpgradeProposalSchema = Yup.object({ + title: Yup.string().required('Title is required'), + description: Yup.string().required('Description is required'), + initialDeposit: Yup.number() + .min(0, 'Initial deposit cannot be negative') + .required('Initial deposit is required'), + applyHeight: Yup.number() + .min(0, 'Apply height cannot be negative') + .required('Apply Height is required'), + planName: Yup.string().required('Plan name is required'), + plan: Yup.string() + .required('Plan is required') + .test('is-json', 'Upgrade plan must be valid JSON', (value: string) => { + try { + JSON.parse(value); + return true; + } catch (error) { + return false; + } + }), +}).required(); + +export function CreateTextProposalForm() { + const toast = useToast(); + const { + register, + handleSubmit, + formState: { errors }, + } = useForm({ + resolver: yupResolver(submitTextProposalSchema), + defaultValues: { + title: 'Test proposal 32312323', + description: + 'Lorem ipsum dolor sit amet consectetur adipisicing elit. Amet aliquam minima sit quaerat! Repudiandae maxime rerum provident, repellat ipsa nesciunt doloribus nam facilis iure modi unde, odio, illo officia voluptatem.', + initialDeposit: 1, + }, + }); + const chains = useSupportedChains(); + const { chain = chains[0] } = useNetwork(); + const { explorer } = getChainParams( + chain.unsupported !== undefined && !chain.unsupported + ? chain.id + : chains[0].id, + ); + const { submitTextProposal } = useProposalActions(); + + const handleSubmitProposal = useCallback( + async (data: CreateTextProposalForm) => { + try { + const submitProposalPromise = submitTextProposal(data); + + await toast.promise(submitProposalPromise, { + loading: Proposal submit in progress, + success: (tx) => { + console.log('Vote successful', { tx }); + const txHash = tx?.txhash; + + return ( + +
+
Your vote will be counted!!!
+
+ + + {getFormattedAddress(txHash)} + +
+
+
+ ); + }, + error: (error) => { + console.error(error); + return For some reason your vote failed.; + }, + }); + } catch (error) { + console.error((error as Error).message); + } + }, + [explorer.cosmos, submitTextProposal, toast], + ); + + const onFormSubmit: SubmitHandler = (data) => { + handleSubmitProposal(data); + }; + + return ( + +
+
+
+ + Text proposal + +
+ +
+
+
+
+ +
+
+ +
+ + {errors.title &&
{errors.title.message}
} +
+ +
+
+ +
+
+ +
+ {errors.description &&
{errors.description.message}
} +
+ +
+
+ +
+
+ +
+ {errors.initialDeposit && ( +
{errors.initialDeposit.message}
+ )} +
+ +
+ +
+
+
+
+
+
+ ); +} + +interface CreateUpgradeProposalForm { + title: string; + description: string; + initialDeposit: number; + applyHeight: number; + planName: string; + plan: string; +} +export function CreateUpgradeProposalForm() { + const toast = useToast(); + const { + register, + handleSubmit, + formState: { errors }, + } = useForm({ + resolver: yupResolver(submitUpgradeProposalSchema), + }); + const chains = useSupportedChains(); + const { chain = chains[0] } = useNetwork(); + const { explorer } = getChainParams( + chain.unsupported !== undefined && !chain.unsupported + ? chain.id + : chains[0].id, + ); + const { submitSuProposal } = useProposalActions(); + + const handleSubmitProposal = useCallback( + async (data: CreateUpgradeProposalForm) => { + try { + const submitProposalPromise = submitSuProposal(data); + + await toast.promise(submitProposalPromise, { + loading: Proposal submit in progress, + success: (tx) => { + console.log('Vote successful', { tx }); + const txHash = tx?.txhash; + + return ( + +
+
Your vote will be counted!!!
+
+ + + {getFormattedAddress(txHash)} + +
+
+
+ ); + }, + error: (error) => { + console.error(error); + return For some reason your vote failed.; + }, + }); + } catch (error) { + console.error((error as Error).message); + } + }, + [explorer.cosmos, submitSuProposal, toast], + ); + + const onFormSubmit: SubmitHandler = (data) => { + handleSubmitProposal(data); + }; + + return ( + +
+
+
+ + Text proposal + +
+ +
+
+
+
+ +
+
+ +
+ + +
+ +
+
+ +
+
+