Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/cfe 206 proposal top #745

Merged
merged 12 commits into from
Feb 1, 2024
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Features

- [#745](https://github.com/alleslabs/celatone-frontend/pull/745) Add proposal top
- [#758](https://github.com/alleslabs/celatone-frontend/pull/758) api v1 - proposal validator votes
- [#757](https://github.com/alleslabs/celatone-frontend/pull/757) api v1 - proposal data
- [#731](https://github.com/alleslabs/celatone-frontend/pull/731) Add proposal detail page structure
Expand Down
10 changes: 5 additions & 5 deletions src/lib/components/ExplorerLink.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ export type LinkType =
| "code_id"
| "block_height"
| "proposal_id"
| "pool_id";
| "pool_id"
| "proposal_id";

interface ExplorerLinkProps extends BoxProps {
value: string;
Expand Down Expand Up @@ -75,9 +76,7 @@ export const getNavigationUrl = ({
url = "/blocks";
break;
case "proposal_id":
url =
explorerConfig.proposal ||
`${lcdEndpoint}/cosmos/gov/v1beta1/proposals`;
url = "/proposals";
break;
case "pool_id":
url = "/pools";
Expand Down Expand Up @@ -189,7 +188,8 @@ export const ExplorerLink = ({
type === "user_address" ||
type === "tx_hash" ||
type === "block_height" ||
type === "pool_id";
type === "pool_id" ||
type === "proposal_id";

const [hrefLink, textValue] = [
getNavigationUrl({
Expand Down
41 changes: 11 additions & 30 deletions src/lib/components/table/proposals/ProposalsTableMobileCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,10 @@ import { Flex, Text } from "@chakra-ui/react";

import { MobileCardTemplate } from "../MobileCardTemplate";
import { MobileLabel } from "../MobileLabel";
import { trackMintScan } from "lib/amplitude";
import { useBaseApiRoute, useCelatoneApp } from "lib/app-provider";
import { ExplorerLink, getNavigationUrl } from "lib/components/ExplorerLink";
import { useInternalNavigate } from "lib/app-provider";
import { ExplorerLink } from "lib/components/ExplorerLink";
import type { Proposal } from "lib/types";
import { ProposalStatus } from "lib/types";
import { openNewTab } from "lib/utils";

import { Proposer } from "./Proposer";
import { ResolvedHeight } from "./ResolvedHeight";
Expand All @@ -21,23 +19,24 @@ export interface ProposalsTableMobileCardProps {
export const ProposalsTableMobileCard = ({
proposal,
}: ProposalsTableMobileCardProps) => {
const isDepositFailed = proposal.status === ProposalStatus.DEPOSIT_FAILED;
const navigate = useInternalNavigate();

const onCardSelect = (proposalId: number) =>
navigate({
pathname: "/proposals/[proposalId]",
query: { proposalId },
});

const isDepositOrVoting =
proposal.status === ProposalStatus.DEPOSIT_PERIOD ||
proposal.status === ProposalStatus.VOTING_PERIOD;
const {
chainConfig: { explorerLink },
} = useCelatoneApp();
const lcdEndpoint = useBaseApiRoute("rest");

return (
<MobileCardTemplate
topContent={
<>
<Flex gap={2} align="center">
<MobileLabel label="Proposal ID" variant="body2" />
<ExplorerLink
isReadOnly={isDepositFailed}
type="proposal_id"
value={proposal.id.toString()}
showCopyOnHover
Expand Down Expand Up @@ -89,25 +88,7 @@ export const ProposalsTableMobileCard = ({
</Flex>
</>
}
onClick={
!isDepositFailed
? () => {
trackMintScan("proposal-detail", {
types: proposal.types,
status: proposal.status,
});
// TOOD: revisit retrieving url (make a proper hook)
openNewTab(
getNavigationUrl({
type: "proposal_id",
explorerConfig: explorerLink,
value: proposal.id.toString(),
lcdEndpoint,
})
);
}
: undefined
}
onClick={() => onCardSelect(proposal.id)}
/>
);
};
58 changes: 20 additions & 38 deletions src/lib/components/table/proposals/ProposalsTableRow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,11 @@ import type { DividerProps, GridProps } from "@chakra-ui/react";
import { Grid } from "@chakra-ui/react";

import { TableRow, TableRowFreeze } from "../tableComponents";
import { trackMintScan } from "lib/amplitude";
import { useBaseApiRoute, useCelatoneApp } from "lib/app-provider";
import { ExplorerLink, getNavigationUrl } from "lib/components/ExplorerLink";
import { useInternalNavigate } from "lib/app-provider";
import { ExplorerLink } from "lib/components/ExplorerLink";
import { StopPropagationBox } from "lib/components/StopPropagationBox";
import type { Option, Proposal } from "lib/types";
import type { Proposal } from "lib/types";
import { ProposalStatus } from "lib/types";
import { openNewTab } from "lib/utils";

import { ProposalTextCell } from "./ProposalTextCell";
import { Proposer } from "./Proposer";
Expand All @@ -27,52 +25,36 @@ export const ProposalsTableRow = ({
templateColumns,
boxShadow,
}: ProposalsTableRowProps) => {
const {
chainConfig: { explorerLink },
} = useCelatoneApp();
const lcdEndpoint = useBaseApiRoute("rest");
const navigate = useInternalNavigate();

const onRowSelect = (proposalId: number) =>
navigate({
pathname: "/proposals/[proposalId]",
query: { proposalId },
});

// TODO - Revisit split columnsWidth
const columnsWidth = templateColumns?.toString().split(" ");
const isDepositFailed = proposal.status === ProposalStatus.DEPOSIT_FAILED;
const isDepositOrVoting =
proposal.status === ProposalStatus.DEPOSIT_PERIOD ||
proposal.status === ProposalStatus.VOTING_PERIOD;

const hoverBg = (): Option<string> => {
if (proposal.isExpedited && isDepositOrVoting) return "primary.background";
return isDepositFailed ? undefined : "gray.900";
};

return (
<Grid
templateColumns={templateColumns}
minW="min-content"
cursor={isDepositFailed ? "default" : "pointer"}
_hover={{ "> div": { bgColor: hoverBg } }}
onClick={
!isDepositFailed
? () => {
trackMintScan("proposal-detail", {
types: proposal.types,
status: proposal.status,
});
// TOOD: revisit retrieving url (make a proper hook)
openNewTab(
getNavigationUrl({
type: "proposal_id",
explorerConfig: explorerLink,
value: proposal.id.toString(),
lcdEndpoint,
})
);
}
: undefined
}
cursor="pointer"
_hover={{
"> div": {
bgColor:
proposal.isExpedited && isDepositOrVoting
? "primary.background"
: "gray.900",
},
}}
onClick={() => onRowSelect(proposal.id)}
>
<TableRowFreeze left="0">
<ExplorerLink
isReadOnly={isDepositFailed}
type="proposal_id"
value={proposal.id.toString()}
showCopyOnHover
Expand Down
158 changes: 158 additions & 0 deletions src/lib/pages/proposal-details/components/ProposalInfo.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
import { Divider, Flex, Text } from "@chakra-ui/react";
import type { ReactNode } from "react";

import { ExplorerLink } from "lib/components/ExplorerLink";
import { MobileLabel, StatusChip } from "lib/components/table";
import type { ProposalData } from "lib/types";
import { ProposalStatus } from "lib/types";
import { formatUTC } from "lib/utils";

interface InfoItemProps {
label: string;
children: ReactNode;
minW?: number;
}

const InfoItem = ({ label, children, minW = 40 }: InfoItemProps) => (
<Flex direction="column" gap={1} minW={minW}>
<MobileLabel label={label} variant="body2" />
{children}
</Flex>
);

interface ProposalStatusProps {
data: ProposalData;
}

const getProposalInfo = (data: ProposalStatusProps["data"]) => {
switch (data.status) {
case ProposalStatus.DEPOSIT_PERIOD:
return (
<InfoItem label="Deposit Start/End">
<Text variant="body2" color="text.dark">
{data.submitTime && data.depositEndTime
? `${formatUTC(data.submitTime)} - ${formatUTC(data.depositEndTime)}`
: "N/A"}
</Text>
</InfoItem>
);
case ProposalStatus.DEPOSIT_FAILED:
return (
<Flex
gap={{ base: 2, xl: 8 }}
direction={{ base: "column", xl: "row" }}
>
<InfoItem label="Failed at block">
{data.resolvedHeight ? (
<ExplorerLink
value={data.resolvedHeight?.toString()}
type="block_height"
showCopyOnHover
/>
) : (
<Text variant="body2" color="text.dark">
N/A
</Text>
)}
</InfoItem>
<InfoItem label="Failed at">
<Text variant="body2" color="text.dark">
{data.resolvedTimestamp
? formatUTC(data.resolvedTimestamp)
: "N/A"}
</Text>
</InfoItem>
</Flex>
);
case ProposalStatus.VOTING_PERIOD:
return (
<InfoItem label="Voting Start/End">
<Text variant="body2" color="text.dark">
{data.votingTime && data.votingEndTime
? `${formatUTC(data.votingTime)} - ${formatUTC(data.votingEndTime)}`
: "N/A"}
</Text>
</InfoItem>
);
case ProposalStatus.PASSED:
case ProposalStatus.FAILED:
case ProposalStatus.REJECTED:
return (
<Flex
gap={{ base: 2, xl: 8 }}
direction={{ base: "column", xl: "row" }}
>
<InfoItem label="Resolved Block Height">
{data.resolvedHeight ? (
<ExplorerLink
value={data.resolvedHeight?.toString()}
type="block_height"
showCopyOnHover
/>
) : (
<Text variant="body2" color="text.dark">
N/A
</Text>
)}
</InfoItem>
<InfoItem label="Resolved at">
<Text variant="body2" color="text.dark">
{data.resolvedTimestamp
? formatUTC(data.resolvedTimestamp)
: "N/A"}
</Text>
</InfoItem>
</Flex>
);
default:
return (
<InfoItem label="Proposal Status">
<Flex>N/A</Flex>
</InfoItem>
);
}
};

export const ProposalInfo = ({ data }: ProposalStatusProps) => (
<Flex
background="gray.900"
borderRadius="8px"
px={4}
py={3}
gap={{ base: 3, lg: 8 }}
direction={{ base: "column", lg: "row" }}
>
<InfoItem label="Proposal Status">
<Flex minW="110px">
<StatusChip status={data.status} />
</Flex>
</InfoItem>
<Flex gap={8}>
{data.createdTxHash && (
<InfoItem label="Created Tx" minW={36}>
<ExplorerLink
value={data.createdTxHash.toUpperCase()}
type="tx_hash"
showCopyOnHover
/>
</InfoItem>
)}
{data.proposer && (
<InfoItem label="Proposer" minW={36}>
<ExplorerLink
value={data.proposer}
type="user_address"
showCopyOnHover
/>
</InfoItem>
)}
</Flex>
<Divider
orientation="vertical"
color="gray.700"
minH="48px"
display={{ base: "none", lg: "flex" }}
/>
<Flex gap={3}>{getProposalInfo(data)}</Flex>
</Flex>
);
Loading
Loading