diff --git a/CHANGELOG.md b/CHANGELOG.md index 90d46cc45..ac5bf413a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -39,6 +39,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Features +- [#782](https://github.com/alleslabs/celatone-frontend/pull/782) Show proposal details on vote details section tabs - [#779](https://github.com/alleslabs/celatone-frontend/pull/779) Proposal period overview voting - no with veto alert - [#778](https://github.com/alleslabs/celatone-frontend/pull/778) Proposal period overview voting - [#775](https://github.com/alleslabs/celatone-frontend/pull/775) Proposal period overview deposit diff --git a/src/lib/pages/proposal-details/components/proposal-overview/status-summary/Countdown.tsx b/src/lib/pages/proposal-details/components/proposal-overview/status-summary/Countdown.tsx index aa82c0748..aea88a389 100644 --- a/src/lib/pages/proposal-details/components/proposal-overview/status-summary/Countdown.tsx +++ b/src/lib/pages/proposal-details/components/proposal-overview/status-summary/Countdown.tsx @@ -2,6 +2,7 @@ import { Spinner } from "@chakra-ui/react"; import dayjs from "dayjs"; import { useRouter } from "next/router"; import plur from "plur"; +import type { ReactNode } from "react"; import { useEffect, useState } from "react"; import { getCurrentDate } from "lib/utils"; @@ -14,11 +15,12 @@ const formatNumber = (num: number) => interface CountdownProps { endTime: Date; + isString: boolean; } -export const Countdown = ({ endTime }: CountdownProps) => { +export const Countdown = ({ endTime, isString }: CountdownProps) => { const router = useRouter(); - const [time, setTime] = useState( + const [time, setTime] = useState( ); @@ -31,7 +33,11 @@ export const Countdown = ({ endTime }: CountdownProps) => { const duration = dayjs.duration(diffTime, "seconds"); const days = duration.days(); - const timestamp = ( + const timestamp = isString ? ( + `${ + days > 0 && `${days.toString()} ${plur("day", days)} ` + }${duration.hours()}:${formatNumber(duration.minutes())}:${formatNumber(duration.seconds())}` + ) : ( <> {days > 0 && ( <> @@ -49,7 +55,7 @@ export const Countdown = ({ endTime }: CountdownProps) => { setTime(timestamp); }, 1000); return () => clearInterval(intervalId); - }, [endTime, router]); + }, [endTime, isString, router]); return time; }; diff --git a/src/lib/pages/proposal-details/components/proposal-overview/status-summary/SummaryStatusTime.tsx b/src/lib/pages/proposal-details/components/proposal-overview/status-summary/SummaryStatusTime.tsx index cfe3ce264..679cf2310 100644 --- a/src/lib/pages/proposal-details/components/proposal-overview/status-summary/SummaryStatusTime.tsx +++ b/src/lib/pages/proposal-details/components/proposal-overview/status-summary/SummaryStatusTime.tsx @@ -25,7 +25,8 @@ export const SummaryStatusTime = ({ proposalData }: StatusTimeProps) => { if (proposalData.status === ProposalStatus.DEPOSIT_PERIOD) return ( - Deposit ends in + Deposit ends in{" "} + ); @@ -34,7 +35,7 @@ export const SummaryStatusTime = ({ proposalData }: StatusTimeProps) => { Voting ends in{" "} {proposalData.votingEndTime ? ( - + ) : ( "N/A" )} diff --git a/src/lib/pages/proposal-details/components/proposal-stepper/StepHelperText.tsx b/src/lib/pages/proposal-details/components/proposal-stepper/StepHelperText.tsx new file mode 100644 index 000000000..181ea3103 --- /dev/null +++ b/src/lib/pages/proposal-details/components/proposal-stepper/StepHelperText.tsx @@ -0,0 +1,69 @@ +/* eslint-disable sonarjs/cognitive-complexity */ +import { Text } from "@chakra-ui/react"; + +import { Countdown } from "../proposal-overview/status-summary/Countdown"; +import type { ProposalData } from "lib/types"; +import { ProposalStatus } from "lib/types"; +import { formatUTC } from "lib/utils"; + +interface StepperHelperTextProps { + step: number; + proposalData: ProposalData; +} + +const StepperHelperTextBody = ({ + step, + proposalData, +}: StepperHelperTextProps) => { + // Deposit Period + if (step === 1) { + if (proposalData.status === ProposalStatus.DEPOSIT_FAILED) + return "The proposal is rejected as it did not meet the required deposit"; + + if ( + proposalData.status === ProposalStatus.CANCELLED && + proposalData.votingTime === null + ) + return `The proposal is cancelled at ${proposalData.resolvedTimestamp ? formatUTC(proposalData.resolvedTimestamp) : "N/A"}`; + + if (proposalData.status === ProposalStatus.DEPOSIT_PERIOD) + return ( + <> + Deposit ends in{" "} + + + ); + + return `The proposal passed the deposit period at ${proposalData.votingTime ? formatUTC(proposalData.votingTime) : "N/A"}`; + } + + // Voting Period + if (proposalData.status === ProposalStatus.DEPOSIT_FAILED) + return "The proposal is rejected as it did not meet the required deposit"; + + if (proposalData.status === ProposalStatus.CANCELLED) + return `The proposal is cancelled during the ${proposalData.votingTime === null ? "deposit" : "voting"} period`; + + if (proposalData.status === ProposalStatus.DEPOSIT_PERIOD) + return "Proposal proceeds to voting period after meeting deposit requirement"; + + if (proposalData.status === ProposalStatus.VOTING_PERIOD) + return ( + <> + Voting ends in{" "} + {proposalData.votingEndTime ? ( + + ) : ( + "N/A" + )} + + ); + + return `The proposal ended with the "${proposalData.status.replace(/([A-Z])/g, " $1").trim()}" result`; +}; + +export const StepperHelperText = (props: StepperHelperTextProps) => ( + + + +); diff --git a/src/lib/pages/proposal-details/components/proposal-stepper/index.tsx b/src/lib/pages/proposal-details/components/proposal-stepper/index.tsx index 1f3418654..83ba1d65a 100644 --- a/src/lib/pages/proposal-details/components/proposal-stepper/index.tsx +++ b/src/lib/pages/proposal-details/components/proposal-stepper/index.tsx @@ -3,8 +3,9 @@ import { Flex, Spacer, Text } from "@chakra-ui/react"; import { ProgressBadge } from "../ProgressBadge"; import type { ProposalData } from "lib/types"; +import { StepperHelperText } from "./StepHelperText"; import { StepIcon } from "./StepIcon"; -import { getProgressBadgeProps, getStepperDescription } from "./utils"; +import { getProgressBadgeProps } from "./utils"; export interface ProposalStepperProps { step: number; @@ -17,19 +18,17 @@ export const ProposalStepper = ({ proposalData, isOverview = false, }: ProposalStepperProps) => ( - + - + {step === 1 ? "Deposit Period" : "Voting Period"} {!isOverview && ( - - {getStepperDescription()} - + )} ); diff --git a/src/lib/pages/proposal-details/components/vote-details/ProposalStepper.tsx b/src/lib/pages/proposal-details/components/vote-details/ProposalStepper.tsx deleted file mode 100644 index 1e0d0ee68..000000000 --- a/src/lib/pages/proposal-details/components/vote-details/ProposalStepper.tsx +++ /dev/null @@ -1,86 +0,0 @@ -import { Flex, Text } from "@chakra-ui/react"; - -import { useMobile } from "lib/app-provider"; - -interface ProposalStepperProps { - title: string; - description: string; - step: number; -} - -export const ProposalStepper = ({ - title, - description, - step, -}: ProposalStepperProps) => { - const isMobile = useMobile(); - return ( - - - - {/* TODO: Color changes when state changes */} - - {step} - - - - {title} - - {!isMobile && ( - - {description} - - )} - - - - - - Waiting For Deposit - - - - {isMobile && ( - - {description} - - )} - - ); -}; diff --git a/src/lib/pages/proposal-details/components/vote-details/VoteDetailsAccordionItem.tsx b/src/lib/pages/proposal-details/components/vote-details/VoteDetailsAccordionItem.tsx new file mode 100644 index 000000000..59c344250 --- /dev/null +++ b/src/lib/pages/proposal-details/components/vote-details/VoteDetailsAccordionItem.tsx @@ -0,0 +1,36 @@ +import { + AccordionButton, + AccordionIcon, + AccordionItem, + AccordionPanel, +} from "@chakra-ui/react"; +import type { ReactNode } from "react"; + +import { ProposalStepper } from "../proposal-stepper"; +import type { ProposalData } from "lib/types"; + +export const VoteDetailsAccordionItem = ({ + step, + proposalData, + children, +}: { + step: number; + proposalData: ProposalData; + children: ReactNode; +}) => ( + + + + + + + {children} + + +); diff --git a/src/lib/pages/proposal-details/components/vote-details/VoteDetailTab.tsx b/src/lib/pages/proposal-details/components/vote-details/VoteDetailsTab.tsx similarity index 59% rename from src/lib/pages/proposal-details/components/vote-details/VoteDetailTab.tsx rename to src/lib/pages/proposal-details/components/vote-details/VoteDetailsTab.tsx index ddb479be3..bdb4ea10b 100644 --- a/src/lib/pages/proposal-details/components/vote-details/VoteDetailTab.tsx +++ b/src/lib/pages/proposal-details/components/vote-details/VoteDetailsTab.tsx @@ -1,26 +1,19 @@ import type { TabProps } from "@chakra-ui/react"; import { Button, useTab, useMultiStyleConfig } from "@chakra-ui/react"; -import type { Nullable } from "lib/types"; +import { ProposalStepper } from "../proposal-stepper"; +import type { ProposalData } from "lib/types"; -import { ProposalStepper } from "./ProposalStepper"; - -interface VoteDetailTabProps extends TabProps { - count?: Nullable; - isLoading?: boolean; - title: string; - description: string; +interface VoteDetailsTabProps extends TabProps { step: number; + proposalData: ProposalData; } -export const VoteDetailTab = ({ - count, - isLoading, - title, - description, +export const VoteDetailsTab = ({ step, + proposalData, ...restProps -}: VoteDetailTabProps) => { +}: VoteDetailsTabProps) => { const tabProps = useTab({ ...restProps }); const styles = useMultiStyleConfig("Tabs", tabProps); @@ -29,22 +22,17 @@ export const VoteDetailTab = ({ __css={styles.tab} display="flex" w="full" - alignItems="center" - fontSize="14px" - fontWeight={700} - lineHeight="24px" - letterSpacing="0.4px" - variant="ghost-gray" mb={0} py={3} borderRadius="8px 8px 0px 0px" + color="text.main" sx={{ "&[aria-selected=true]": { background: "gray.800", border: "1px solid", borderColor: "gray.700", opacity: "100%", - borderBottomColor: "transparent", + borderBottomColor: "gray.800", }, "&[aria-selected=false]": { background: "transparent", @@ -59,7 +47,7 @@ export const VoteDetailTab = ({ }} {...tabProps} > - + ); }; diff --git a/src/lib/pages/proposal-details/components/vote-details/index.tsx b/src/lib/pages/proposal-details/components/vote-details/index.tsx index 9e73d40f5..6da497586 100644 --- a/src/lib/pages/proposal-details/components/vote-details/index.tsx +++ b/src/lib/pages/proposal-details/components/vote-details/index.tsx @@ -1,85 +1,36 @@ import { Accordion, - AccordionButton, - AccordionIcon, - AccordionItem, - AccordionPanel, Flex, TabList, TabPanel, TabPanels, Tabs, } from "@chakra-ui/react"; -import { useMemo, type ReactNode } from "react"; import { useMobile } from "lib/app-provider"; +import type { ProposalData } from "lib/types"; import { DepositPeriodSection } from "./deposit-period/DepositPeriodSection"; -import { ProposalStepper } from "./ProposalStepper"; -import { VoteDetailTab } from "./VoteDetailTab"; +import { VoteDetailsAccordionItem } from "./VoteDetailsAccordionItem"; +import { VoteDetailsTab } from "./VoteDetailsTab"; import { VotingPeriod } from "./voting-period"; -const AccordionItemComponent = ({ - step, - title, - description, - children, -}: { - step: number; - title: string; - description: string; - children: ReactNode; -}) => ( - - - - - - - {children} - - -); - interface VoteDetailsProps { - id: number; + proposalData: ProposalData; } -export const VoteDetails = ({ id }: VoteDetailsProps) => { +export const VoteDetails = ({ proposalData }: VoteDetailsProps) => { const isMobile = useMobile(); - const accordionData = useMemo( - () => [ - { - step: 1, - title: "Deposit Period", - description: "Deposit ends in 4 days 21:00:11", - content: , - }, - { - step: 2, - title: "Voting Period", - description: "Voting ends in 3 days 12:00:10", - content: , - }, - ], - // TODO: Add dependencies - [id] - ); return isMobile ? ( - {accordionData.map((item) => ( - - {item.content} - - ))} + + + + + + ) : ( @@ -87,14 +38,8 @@ export const VoteDetails = ({ id }: VoteDetailsProps) => { {/* To add index to Tabs */} - {accordionData.map((item) => ( - - ))} + + { borderTopColor="transparent" borderRadius="0px 0px 8px 8px" > - {accordionData.map((item) => ( - {item.content} - ))} + + + + + + diff --git a/src/lib/pages/proposal-details/index.tsx b/src/lib/pages/proposal-details/index.tsx index b7b60c151..3998e3ab3 100644 --- a/src/lib/pages/proposal-details/index.tsx +++ b/src/lib/pages/proposal-details/index.tsx @@ -80,7 +80,7 @@ const ProposalDetailsBody = ({ /> - +