Skip to content

Commit

Permalink
Create governance proposal page
Browse files Browse the repository at this point in the history
Add DomPurify for sanitize micromark result
  • Loading branch information
jmrossy committed Feb 19, 2024
1 parent e15b0b7 commit 5b6f77e
Show file tree
Hide file tree
Showing 13 changed files with 366 additions and 54 deletions.
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
"@vercel/analytics": "^1.1.1",
"bignumber.js": "^9.1.2",
"clsx": "^2.0.0",
"dompurify": "^3.0.8",
"formik": "2.4.5",
"micromark": "^4.0.0",
"next": "14.1.0",
Expand All @@ -40,6 +41,7 @@
},
"devDependencies": {
"@tanstack/eslint-plugin-query": "^5.17.7",
"@types/dompurify": "^3",
"@types/jest": "^29.5.11",
"@types/node": "^20.10.4",
"@types/react": "^18.2.45",
Expand Down
69 changes: 69 additions & 0 deletions src/app/governance/[id]/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
'use client';

import { useMemo } from 'react';
import { BackLink } from 'src/components/buttons/BackLink';
import { Section } from 'src/components/layout/Section';
import { ProposalBadgeRow } from 'src/features/governance/ProposalCard';
import {
MergedProposalData,
useGovernanceProposals,
} from 'src/features/governance/useGovernanceProposals';
import { useProposalContent } from 'src/features/governance/useProposalContent';
import { usePageInvariant } from 'src/utils/navigation';
import { trimToLength } from 'src/utils/strings';

const ID_PARAM_REGEX = /^(cgp-)?(\d+)$/;

export const dynamicParams = true;

export default function Page({ params: { id } }: { params: { id: string } }) {
const { proposals } = useGovernanceProposals();

const proposal = useMemo(() => {
if (!proposals || !id) return undefined;
const matches = ID_PARAM_REGEX.exec(id);
if (matches?.length === 2) {
const propId = parseInt(matches[1]);
return proposals.find((p) => p.proposal?.id === propId);
} else if (matches?.length === 3) {
const cgpId = parseInt(matches[2]);
return proposals.find((p) => p.metadata?.cgp === cgpId);
} else {
return undefined;
}
}, [proposals, id]);

usePageInvariant(!proposals || proposal, '/governance', 'Proposal not found');
if (!proposal) return null;

return (
<Section containerClassName="space-y-4 mt-4">
<div className="flex flex-col md:flex-row">
<ProposalContent data={proposal} />
<ProposalChainData data={proposal} />
</div>
</Section>
);
}

function ProposalContent({ data }: { data: MergedProposalData }) {
const { proposal, metadata } = data;
const title = trimToLength(metadata?.title || `Proposal #${proposal?.id}`, 80);

//TODO loading/err
const { content } = useProposalContent(metadata);

return (
<div className="space-y-3">
<BackLink href="/governance">Browse proposals</BackLink>
<h1 className="font-serif text-xl md:text-2xl">{title}</h1>
<ProposalBadgeRow data={data} showProposer />
<div dangerouslySetInnerHTML={{ __html: content || '' }}></div>
</div>
);
}

function ProposalChainData({ data: { proposal } }: { data: MergedProposalData }) {
if (!proposal) return null;
return <div>TODO</div>;
}
10 changes: 2 additions & 8 deletions src/app/staking/[address]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,14 @@ import { useMemo, useState } from 'react';
import { PieChart } from 'react-minimal-pie-chart';
import { toast } from 'react-toastify';
import { Spinner } from 'src/components/animation/Spinner';
import { BackLink } from 'src/components/buttons/BackLink';
import { ExternalLink } from 'src/components/buttons/ExternalLink';
import { IconButton } from 'src/components/buttons/IconButton';
import { OutlineButton } from 'src/components/buttons/OutlineButton';
import { SolidButton } from 'src/components/buttons/SolidButton';
import { TabHeaderButton } from 'src/components/buttons/TabHeaderButton';
import { TextLink } from 'src/components/buttons/TextLink';
import { HeatmapLines } from 'src/components/charts/Heatmap';
import { sortAndCombineChartData } from 'src/components/charts/chartData';
import { ArrowIcon } from 'src/components/icons/Arrow';
import { Checkmark } from 'src/components/icons/Checkmark';
import { Circle } from 'src/components/icons/Circle';
import { Identicon } from 'src/components/icons/Identicon';
Expand Down Expand Up @@ -85,12 +84,7 @@ function HeaderSection({ group }: { group?: ValidatorGroup }) {

return (
<div>
<TextLink href="/" className="font-medium text-taupe-600">
<div className="flex items-center text-sm">
<ArrowIcon width={20} height={20} direction="w" fill={Color.Wood} />
<span>Browse Validators</span>
</div>
</TextLink>
<BackLink href="/">Browse validators</BackLink>
<div className="mt-6 flex w-full flex-col items-stretch gap-3 sm:flex-row sm:items-center sm:justify-between sm:gap-40">
<div className="flex items-center space-x-3 sm:space-x-6">
<ValidatorGroupLogo address={address} size={90} />
Expand Down
20 changes: 20 additions & 0 deletions src/components/buttons/BackLink.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { PropsWithChildren } from 'react';
import { TextLink } from 'src/components/buttons/TextLink';
import { ArrowIcon } from 'src/components/icons/Arrow';
import { Color } from 'src/styles/Color';

interface Props {
href: string;
className?: string;
}

export function BackLink({ href, className, children }: PropsWithChildren<Props>) {
return (
<TextLink href={href} className={`font-medium text-taupe-600 ${className}`}>
<div className="flex items-center text-sm">
<ArrowIcon width={20} height={20} direction="w" fill={Color.Wood} />
<span>{children}</span>
</div>
</TextLink>
);
}
6 changes: 2 additions & 4 deletions src/components/buttons/TextLink.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,13 @@ interface Props {
className?: string;
}

export function TextLink(props: PropsWithChildren<Props>) {
const { href, className } = props;

export function TextLink({ href, className, children }: PropsWithChildren<Props>) {
return (
<Link
className={`cursor-pointer underline-offset-2 transition-all hover:underline active:opacity-80 ${className}`}
href={href}
>
{props.children}
{children}
</Link>
);
}
Loading

0 comments on commit 5b6f77e

Please sign in to comment.