diff --git a/.github/workflows/merge.yaml b/.github/workflows/merge.yaml index e0591e18..f37b64fa 100644 --- a/.github/workflows/merge.yaml +++ b/.github/workflows/merge.yaml @@ -134,7 +134,7 @@ jobs: NEXT_PUBLIC_USERSNAP_SPACE_API_KEY=${{ secrets.QA_NEXT_PUBLIC_USERSNAP_SPACE_API_KEY }} NEXT_PUBLIC_USERSNAP_PROJECT_API_KEY=${{ secrets.QA_NEXT_PUBLIC_USERSNAP_PROJECT_API_KEY }} NEXT_PUBLIC_HIDDEN_USERSNAP_PROJECT_IDS=${{ secrets.QA_NEXT_PUBLIC_HIDDEN_USERSNAP_PROJECT_IDS }} - NEXT_PUBLIC_IS_MAINNET=${{ secrets.QA_NEXT_PUBLIC_IS_MAINNET }} + NEXT_PUBLIC_IS_MAINNET=${{ secrets.QA_NEXT_PUBLIC_IS_MAINNET }}g - name: Scan Docker image with Dockle id: dockle diff --git a/.github/workflows/pr.yaml b/.github/workflows/pr.yaml index 8856e2dc..55a52173 100644 --- a/.github/workflows/pr.yaml +++ b/.github/workflows/pr.yaml @@ -117,7 +117,7 @@ jobs: cache-from: type=local,src=/tmp/.buildx-cache cache-to: type=local,dest=/tmp/.buildx-cache outputs: type=docker,dest=/tmp/image-${{ matrix.name }}-${{ github.sha }}-pr.tar - build-args: | + build-args: | NEXT_PUBLIC_API_URL=${{ secrets.QA_NEXT_PUBLIC_API_URL }} NEXT_PUBLIC_USERSNAP_SPACE_API_KEY=${{ secrets.QA_NEXT_PUBLIC_USERSNAP_SPACE_API_KEY }} NEXT_PUBLIC_USERSNAP_PROJECT_API_KEY=${{ secrets.QA_NEXT_PUBLIC_USERSNAP_PROJECT_API_KEY }} diff --git a/backend/src/users/api/request/update-user.request.ts b/backend/src/users/api/request/update-user.request.ts index 77d72556..a9cc6b81 100644 --- a/backend/src/users/api/request/update-user.request.ts +++ b/backend/src/users/api/request/update-user.request.ts @@ -15,7 +15,7 @@ export class UpdateUserRequest { }) @MinLength(2, { message: `Minimum character length is 2` }) @MaxLength(30, { message: `Maximum character length is 30` }) - @Matches(/^[a-zA-Z0-9_.\s]+$/, { + @Matches(/^[a-zA-Z0-9_|.\s]+$/, { message: `Name can't contain special characters & symbols`, }) @IsString() diff --git a/frontend/messages/de.json b/frontend/messages/de.json index e68e972d..b068c1a6 100644 --- a/frontend/messages/de.json +++ b/frontend/messages/de.json @@ -30,6 +30,7 @@ "govAction": "Governance Action", "govActionCategoryShort": "GA Category", "voted": "Voted", + "time": "Time", "rationale": "Rationale", "actionTitle": "Show more", "notAvailable": "Not Available", @@ -225,29 +226,15 @@ "previewRationale": { "headline": "Rationale", "description": "Please update rationale for your vote on specific governance action.", - "noRationaleUrl": "A rationale has not been provided for this vote", "rationaleLink": "Rationale link", + "rationale": "Rationale", + "notAvailable": "Not Available", + "governanceActionStatus": "Governance Action Status", "governanceActionCategory": "Governance Action Category", "governanceActionId": "Governance Action ID", "voted": "Voted", - "submissionDate": "Submission date", - "expiryDate": "Expiry date", - "voteSubmissionDate": "Vote submission date", - "tooltips": { - "expiryDate": { - "heading": "Expiry Date", - "paragraphOne": "The date when the governance action will expiry if it doesn’t reach ratification thresholds.", - "paragraphTwo": "IMPORTANT: If the governance action is ratified before the expiry date it will be considered ratified and it will not be available to vote on afterwards." - }, - "submissionDate": { - "heading": "Submission Date", - "paragraphOne": "The date when the governance action was submitted on-chain.", - "vote": { - "heading": "Vote Submission Date", - "paragraphOne": "The date when the vote was submitted on-chain." - } - } - }, + "submissionDate": "GA submitted on:", + "expiryDate": "GA expiration date:", "alerts": { "error": "Error fetching rationale data" } diff --git a/frontend/messages/en.json b/frontend/messages/en.json index 053776d0..b4a9f141 100644 --- a/frontend/messages/en.json +++ b/frontend/messages/en.json @@ -30,6 +30,7 @@ "govAction": "Governance Action", "govActionCategoryShort": "GA Category", "voted": "Voted", + "time": "Time", "rationale": "Rationale", "actionTitle": "Show more", "notAvailable": "Not Available", @@ -225,29 +226,15 @@ "previewRationale": { "headline": "Rationale", "description": "Please update rationale for your vote on specific governance action.", - "noRationaleUrl": "A rationale has not been provided for this vote", "rationaleLink": "Rationale link", + "rationale": "Rationale", + "notAvailable": "Not Available", + "governanceActionStatus": "Governance Action Status", "governanceActionCategory": "Governance Action Category", "governanceActionId": "Governance Action ID", "voted": "Voted", - "submissionDate": "Submission date", - "expiryDate": "Expiry date", - "voteSubmissionDate": "Vote submission date", - "tooltips": { - "expiryDate": { - "heading": "Expiry Date", - "paragraphOne": "The date when the governance action will expiry if it doesn’t reach ratification thresholds.", - "paragraphTwo": "IMPORTANT: If the governance action is ratified before the expiry date it will be considered ratified and it will not be available to vote on afterwards." - }, - "submissionDate": { - "heading": "Submission Date", - "paragraphOne": "The date when the governance action was submitted on-chain.", - "vote": { - "heading": "Vote Submission Date", - "paragraphOne": "The date when the vote was submitted on-chain." - } - } - }, + "submissionDate": "GA submitted on:", + "expiryDate": "GA expiration date:", "alerts": { "error": "Error fetching rationale data" } diff --git a/frontend/src/app/[locale]/loading.tsx b/frontend/src/app/[locale]/loading.tsx new file mode 100644 index 00000000..a58d77b5 --- /dev/null +++ b/frontend/src/app/[locale]/loading.tsx @@ -0,0 +1,16 @@ +import { Box, CircularProgress } from "@mui/material"; + +export default function CenteredLoading() { + return ( + + + + ); +} diff --git a/frontend/src/components/atoms/modal/ModalWrapper.tsx b/frontend/src/components/atoms/modal/ModalWrapper.tsx index eb39bd05..36f882f1 100644 --- a/frontend/src/components/atoms/modal/ModalWrapper.tsx +++ b/frontend/src/components/atoms/modal/ModalWrapper.tsx @@ -1,11 +1,11 @@ "use client"; -import { SxProps, styled } from "@mui/material/styles"; +import { styled, SxProps } from "@mui/material/styles"; -import { customPalette, ICONS } from "@consts"; -import { callAll } from "@utils"; import { useModal } from "@/context"; import { useScreenDimension } from "@/lib/hooks"; +import { customPalette, ICONS } from "@consts"; +import { callAll } from "@utils"; type ModalVariant = "modal" | "popup" | "wide"; interface Props { @@ -27,7 +27,7 @@ export const ModalWrapper = ({ icon, scrollable, hideCloseButton = true, - onClose, + onClose }: Props) => { const { closeModal } = useModal(); const { isMobile } = useScreenDimension(); @@ -79,6 +79,7 @@ export const BaseWrapper = styled("div")<{ transform: translate(-50%, -50%); overflow-y: ${({ scrollable }) => scrollable && "scroll"}; overflow-x: hidden; + scrollbar-width: ${({ scrollable }) => (scrollable ? "auto" : "none")}; @media (max-width: ${700}px) { overflow: scroll; } diff --git a/frontend/src/components/organisms/Constitution/Constitution.tsx b/frontend/src/components/organisms/Constitution/Constitution.tsx index d7ad6454..601a8151 100644 --- a/frontend/src/components/organisms/Constitution/Constitution.tsx +++ b/frontend/src/components/organisms/Constitution/Constitution.tsx @@ -16,6 +16,7 @@ import { Heading1, Heading2, Heading3, + Heading5, ListItem, NavDrawerDesktop, Paragraph, @@ -66,6 +67,7 @@ export function Constitution({ constitution, metadata }: ConstitutionProps) { h1: Heading1, h2: Heading2, h3: Heading3, + h5: Heading5, p: Paragraph, li: ListItem, code: Code, diff --git a/frontend/src/components/organisms/Constitution/ConstitutionSidebar.tsx b/frontend/src/components/organisms/Constitution/ConstitutionSidebar.tsx index 1a4608da..dae59467 100644 --- a/frontend/src/components/organisms/Constitution/ConstitutionSidebar.tsx +++ b/frontend/src/components/organisms/Constitution/ConstitutionSidebar.tsx @@ -28,7 +28,7 @@ export const ConstitutionSidebar = ({ tableOfContents, metadata }) => { justifyContent="left" padding={2} pt={{ xxs: 0, md: 2 }} - px={{ xxs: 2, md: 3 }} + px={{ xxs: 1, md: 2 }} flexWrap="nowrap" > {/* @@ -45,7 +45,7 @@ export const ConstitutionSidebar = ({ tableOfContents, metadata }) => { container direction="column" width={{ xxs: "100%", lg: "340px" }} - px={{ xxs: 1, md: 1 }} + px={{ xxs: 0, md: 0 }} > {/* {tab === "revisions" ? ( diff --git a/frontend/src/components/organisms/Constitution/MDXComponents.tsx b/frontend/src/components/organisms/Constitution/MDXComponents.tsx index 5291e7e7..e7304e57 100644 --- a/frontend/src/components/organisms/Constitution/MDXComponents.tsx +++ b/frontend/src/components/organisms/Constitution/MDXComponents.tsx @@ -79,6 +79,21 @@ export const Heading3 = ({ children, id }) => ( ); +export const Heading5 = ({ children }) => ( + + {children} + +); export const Paragraph = ({ children, id }) => ( <> @@ -105,7 +120,8 @@ export const ListItem = ({ children, id }) => ( display: "flex", flexDirection: "column", alignItems: "flex-start", - justifyContent: "center" + justifyContent: "center", + wordBreak: "break-all" }} > {children} @@ -131,6 +147,7 @@ export const Code = ({ children }) => ( export const TABLE_OF_CONTENTS_WRAPPER_STYLE_PROPS = { backgroundColor: customPalette.neutralWhite, borderRadius: "16px", + padding: "12px", "& ol.toc-level": { margin: 0 }, diff --git a/frontend/src/components/organisms/Constitution/TOCAccordion.tsx b/frontend/src/components/organisms/Constitution/TOCAccordion.tsx index 6d0336b6..9af16484 100644 --- a/frontend/src/components/organisms/Constitution/TOCAccordion.tsx +++ b/frontend/src/components/organisms/Constitution/TOCAccordion.tsx @@ -1,5 +1,4 @@ "use client"; -import { customPalette } from "@/constants"; import ExpandMoreIcon from "@mui/icons-material/ExpandMore"; import { Accordion, @@ -35,7 +34,6 @@ export const TocAccordion = ({ children }) => { elevation={0} sx={{ boxShadow: "none", - padding: 0, "&:before": { display: "none" }, @@ -48,12 +46,7 @@ export const TocAccordion = ({ children }) => { sx={{ borderRadius: "30px", minHeight: "56px", - "&:hover": { - backgroundColor: customPalette.accordionBg - }, - "&.Mui-expanded": { - backgroundColor: customPalette.accordionBg - }, + padding: 0, "& a": { "&:active": { pointerEvents: "none" // disables the href activation on click but keep tooltip showing @@ -100,11 +93,9 @@ export const TocAccordion = ({ children }) => { alignItems: "center", justifyContent: "left", listStyleType: "none", - padding: "0 16px", + padding: 0, width: "100%", - "&:hover": { - backgroundColor: customPalette.accordionBg - }, + "& li": { display: "flex", alignItems: "center" @@ -117,7 +108,7 @@ export const TocAccordion = ({ children }) => { void; - disabled: boolean; } /** * TOCLink Component @@ -19,7 +18,7 @@ interface Props { * @param {Function} props.callback - A callback function to be executed after the link is clicked. */ -const TOCLink = ({ href, children, callback, disabled }: Props) => { +const TOCLink = ({ href, children, callback }: Props) => { const [isActive, setIsActive] = useState(false); const [isTruncated, setIsTruncated] = useState(false); const linkRef = useRef(null); @@ -68,7 +67,13 @@ const TOCLink = ({ href, children, callback, disabled }: Props) => { }, [children]); return ( - + { style={{ color: customPalette.textBlack, textDecoration: "none", - maxWidth: "260px", + maxWidth: "292px", whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis", - display: "inline-block" + display: "inline-block", + backgroundColor: isActive ? customPalette.accordionBg : undefined, + borderRadius: "30px", + padding: "0 16px", + boxSizing: "border-box" }} > {children} diff --git a/frontend/src/components/organisms/Constitution/TOCNested.tsx b/frontend/src/components/organisms/Constitution/TOCNested.tsx index 1f671c24..a6afbbfa 100644 --- a/frontend/src/components/organisms/Constitution/TOCNested.tsx +++ b/frontend/src/components/organisms/Constitution/TOCNested.tsx @@ -1,4 +1,3 @@ -import { customPalette } from "@/constants"; import ExpandMoreIcon from "@mui/icons-material/ExpandMore"; import { Accordion, AccordionDetails, AccordionSummary } from "@mui/material"; @@ -23,12 +22,8 @@ export const TocNested = ({ headings }) => { sx={{ borderRadius: "30px", minHeight: "56px", - "&:hover": { - backgroundColor: customPalette.accordionBg - }, - "&.Mui-expanded": { - backgroundColor: customPalette.accordionBg - }, + padding: 0, + "& a": { "&:active": { pointerEvents: "none" // disables the href activation on click but keep tooltip showing diff --git a/frontend/src/components/organisms/Footer/Footer.tsx b/frontend/src/components/organisms/Footer/Footer.tsx index 6ca6885f..cf22f562 100644 --- a/frontend/src/components/organisms/Footer/Footer.tsx +++ b/frontend/src/components/organisms/Footer/Footer.tsx @@ -66,14 +66,29 @@ export const Footer = ({ variant="caption" data-testid="footer-privacy-policy-hyperlink" > - {t("privacyPolicy")} + + {t("privacyPolicy")} + + - {t("termsOfService")} + + {t("termsOfService")} + {!userSession && showSignIn && ( diff --git a/frontend/src/components/organisms/LatestUpdates.tsx b/frontend/src/components/organisms/LatestUpdates.tsx index 0e8e9396..5d4e97d4 100644 --- a/frontend/src/components/organisms/LatestUpdates.tsx +++ b/frontend/src/components/organisms/LatestUpdates.tsx @@ -47,7 +47,9 @@ export const LatestUpdates = ({ end_time: action.gov_action_proposal_end_time, vote: action.value, reasoning_title: action.reasoning_title, - rationale_url: action.rationale_url + rationale_url: action.rationale_url, + status: action.gov_action_proposal_status, + title: action.gov_action_proposal_title } } }); diff --git a/frontend/src/components/organisms/Modals/GovActionModal.tsx b/frontend/src/components/organisms/Modals/GovActionModal.tsx index f6ae2723..7efe73f6 100644 --- a/frontend/src/components/organisms/Modals/GovActionModal.tsx +++ b/frontend/src/components/organisms/Modals/GovActionModal.tsx @@ -1,178 +1,178 @@ -"use client"; - -import { useSnackbar } from "@/context/snackbar"; -import { getGovernanceMetadata } from "@/lib/api"; -import { - Button, - ModalHeader, - ModalWrapper, - OutlinedLightButton, - Typography -} from "@atoms"; -import { customPalette, IMAGES } from "@consts"; -import { useModal } from "@context"; -import { useScreenDimension } from "@hooks"; -import { CopyCard, Loading } from "@molecules"; -import { Box } from "@mui/material"; -import { GovActionModalState } from "@organisms"; -import { - formatDisplayDate, - getProposalTypeLabel, - getShortenedGovActionId, - isResponseErrorI -} from "@utils"; -import { useTranslations } from "next-intl"; -import { useEffect, useState } from "react"; -import { GovActionMetadata } from "../types"; - -export const GovActionModal = () => { - const t = useTranslations("Modals"); - const { closeModal, state } = useModal(); - const [govAction, setGovAction] = useState(); - const { addErrorAlert } = useSnackbar(); - const { isMobile } = useScreenDimension(); - - const onClick = () => { - closeModal(); - }; - - useEffect(() => { - async function fetchGAMetadata(id) { - const meta = await getGovernanceMetadata(id); - if (isResponseErrorI(meta)) { - addErrorAlert(meta.error); - closeModal(); - } else { - setGovAction(meta); - } - } - - if (state.id) { - fetchGAMetadata(state.id); - } - }, [state.id]); - - return ( - - {govAction ? ( - <> - - - icon - - - {govAction.title} - - - - - {govAction?.abstract} - - - - - - - {t("govActionModal.govActionCategory")} - - - {getProposalTypeLabel(govAction.type)} - - - - - {t("govActionModal.gaStatus")} - - - - {govAction.status} - - - - - - - {t("govActionModal.submitTime")} - - - {formatDisplayDate(govAction.submit_time)} - - - {govAction.end_time && ( - - - {t("govActionModal.endTime")} - - - {formatDisplayDate(govAction.end_time)} - - - )} - - - - - ) : ( - - )} - - ); -}; +"use client"; + +import { useSnackbar } from "@/context/snackbar"; +import { getGovernanceMetadata } from "@/lib/api"; +import { + Button, + ModalHeader, + ModalWrapper, + OutlinedLightButton, + Typography +} from "@atoms"; +import { customPalette, IMAGES } from "@consts"; +import { useModal } from "@context"; +import { useScreenDimension } from "@hooks"; +import { CopyCard, Loading } from "@molecules"; +import { Box } from "@mui/material"; +import { GovActionModalState } from "@organisms"; +import { + formatDisplayDate, + getProposalTypeLabel, + getShortenedGovActionId, + isResponseErrorI +} from "@utils"; +import { useTranslations } from "next-intl"; +import { useEffect, useState } from "react"; +import { GovActionMetadata } from "../types"; + +export const GovActionModal = () => { + const t = useTranslations("Modals"); + const { closeModal, state } = useModal(); + const [govAction, setGovAction] = useState(); + const { addErrorAlert } = useSnackbar(); + const { isMobile } = useScreenDimension(); + + const onClick = () => { + closeModal(); + }; + + useEffect(() => { + async function fetchGAMetadata(id) { + const meta = await getGovernanceMetadata(id); + if (isResponseErrorI(meta)) { + addErrorAlert(meta.error); + closeModal(); + } else { + setGovAction(meta); + } + } + + if (state.id) { + fetchGAMetadata(state.id); + } + }, [state.id]); + + return ( + + {govAction ? ( + <> + + + icon + + + {govAction.title} + + + + + {govAction?.abstract} + + + + + + + {t("govActionModal.govActionCategory")} + + + {getProposalTypeLabel(govAction.type)} + + + + + {t("govActionModal.gaStatus")} + + + + {govAction.status} + + + + + + + {t("govActionModal.submitTime")} + + + {formatDisplayDate(govAction.submit_time)} + + + {govAction.end_time && ( + + + {t("govActionModal.endTime")} + + + {formatDisplayDate(govAction.end_time)} + + + )} + + + + + ) : ( + + )} + + ); +}; diff --git a/frontend/src/components/organisms/Modals/PreviewReasoningModal.tsx b/frontend/src/components/organisms/Modals/PreviewReasoningModal.tsx index 592ad93f..8edb512d 100644 --- a/frontend/src/components/organisms/Modals/PreviewReasoningModal.tsx +++ b/frontend/src/components/organisms/Modals/PreviewReasoningModal.tsx @@ -1,116 +1,61 @@ "use client"; import { CopyPill } from "@/components/molecules"; -import { Reasoning } from "@/components/molecules/Reasoning"; import { useSnackbar } from "@/context/snackbar"; -import { ReasoningResponseI } from "@/lib/requests"; +import { getGovernanceMetadata } from "@/lib/api"; import { Button, ModalHeader, ModalWrapper, OutlinedLightButton, - Tooltip, Typography, VotePill } from "@atoms"; -import { customPalette, IMAGES } from "@consts"; +import { IMAGES } from "@consts"; import { useModal } from "@context"; import { useScreenDimension } from "@hooks"; -import InfoOutlinedIcon from "@mui/icons-material/InfoOutlined"; import { Box } from "@mui/material"; import { formatDisplayDate, getProposalTypeLabel, - getShortenedGovActionId + getShortenedGovActionId, + isResponseErrorI } from "@utils"; import { useTranslations } from "next-intl"; import { useEffect, useState } from "react"; -import { OpenPreviewReasoningModal } from "../types"; +import { GovActionMetadata, OpenPreviewReasoningModal } from "../types"; -interface Reasoning extends Omit { - comment: string; -} export const PreviewReasoningModal = () => { const t = useTranslations("Modals"); const { closeModal, state: { govAction, onActionClick, actionTitle } } = useModal(); - const [reasoning, setReasoning] = useState(null); const onClose = () => { closeModal(); }; const { isMobile } = useScreenDimension(); const { addErrorAlert } = useSnackbar(); + const [govMetadata, setGovMetadata] = useState(); useEffect(() => { - // async function fetchData(id: string) { - // const response = await getReasoningData(id); - // if (isResponseErrorI(response)) { - // if (response.statusCode !== 404 && response.statusCode !== 401) { - // addErrorAlert(response.error); - // closeModal(); - // } - // } else { - // const contents = JSON.parse(response.contents); - // setReasoning({ ...response, comment: contents.body.comment }); - // } - // } - // if (govAction.reasoning_title && govAction.reasoning_comment) { - // setReasoning({ - // comment: govAction.reasoning_comment, - // title: govAction.reasoning_title, - // }); - // } else if (govAction?.id) { - // fetchData(govAction.id); - // } - }, [govAction?.id]); + async function fetchGAMetadata(id) { + const meta = await getGovernanceMetadata(id); + if (isResponseErrorI(meta)) { + addErrorAlert(meta.error); + closeModal(); + } else { + setGovMetadata(meta); + } + } + + if (govAction.id) { + fetchGAMetadata(govAction.id); + } + }, [govAction.id]); + + if (!govMetadata) return null; - const DisplayDate = ({ - bgColor = "#D6E2FF80", - title, - date, - tooltipHeading, - tooltipParagraph, - dataTestId - }) => { - return ( - - - {title} - - - {formatDisplayDate(date)} - - - - - - ); - }; return ( @@ -122,62 +67,30 @@ export const PreviewReasoningModal = () => { src={IMAGES.pastelAddMember} /> - - {t("previewRationale.headline")} + + {govAction.title} - {!govAction.rationale_url && ( - - {t("previewRationale.noRationaleUrl")} - - )} - {/* {reasoning && ( - + - - - )} */} - {govAction.rationale_url && ( - - - {t("previewRationale.rationaleLink")} - - - - )} + {govMetadata.abstract} + + {t("previewRationale.governanceActionId")} @@ -202,6 +115,19 @@ export const PreviewReasoningModal = () => { {getProposalTypeLabel(govAction.type)} + + + {t("previewRationale.governanceActionStatus")} + + + + {govAction.status} + + + {govAction.vote && ( @@ -216,44 +142,73 @@ export const PreviewReasoningModal = () => { )} - - {govAction.submit_time && ( - - )} - {govAction.vote_submit_time && ( - + + {t("previewRationale.rationale")} + + {govAction.rationale_url ? ( + + ) : ( + + {t("previewRationale.notAvailable")} + )} - dataTestId="vote-submit-date-row" - /> + + + + {govMetadata.submit_time && ( + + + {t("previewRationale.submissionDate")} + + + {formatDisplayDate(govAction.submit_time)} + + )} - {govAction.end_time && ( - + {govMetadata?.end_time && ( + + + {t("previewRationale.expiryDate")} + + + {formatDisplayDate(govAction.end_time)} + + )} - { const { state, closeModal } = useModal(); @@ -35,7 +35,7 @@ export const SignUpModal = () => { handleSubmit, formState: { errors }, control, - setValue, + setValue } = useForm(); useEffect(() => { @@ -99,8 +99,16 @@ export const SignUpModal = () => { label={t("signUp.fields.displayName.label")} errors={errors} control={control} - {...register("name", { required: "Display name is required" })} + {...register("name", { + pattern: { + value: PATTERNS.username, + message: + "Display name can only contain letters, numbers, spaces, underscores, pipes, and periods" + }, + required: "Display name is required" + })} /> + { {t("signUp.fields.hotCredential.label")} { {...register("hotAddress", { pattern: { value: PATTERNS.hotAddress, - message: "Entered value does not match the expected format", - }, + message: "Entered value does not match the expected format" + } })} /> { fileSize: (file) => !file || file.size / (1024 * 1024) < PROFILE_PICTURE_MAX_FILE_SIZE || - "The file size should be less than 5MB", - }, + "The file size should be less than 5MB" + } })} > {t("signUp.fields.upload")} {state.showCloseButton ? ( diff --git a/frontend/src/components/organisms/MyActions.tsx b/frontend/src/components/organisms/MyActions.tsx index 3fea4807..d957e4b2 100644 --- a/frontend/src/components/organisms/MyActions.tsx +++ b/frontend/src/components/organisms/MyActions.tsx @@ -55,13 +55,15 @@ export const MyActions = ({ type: action.gov_action_proposal_type, submit_time: null, //todo, update BE response end_time: action.gov_action_proposal_end_time, - vote_submit_time: action.vote_submit_time, - vote: action.value + vote: action.value, + reasoning_title: action.reasoning_title, + rationale_url: action.rationale_url, + status: action.gov_action_proposal_status, + title: action.gov_action_proposal_title } } }); }; - const params: Record = { search: searchText || null, govActionType: diff --git a/frontend/src/components/organisms/TopNavigation/DrawerMobile.tsx b/frontend/src/components/organisms/TopNavigation/DrawerMobile.tsx index a2dfcfce..9dc54c89 100644 --- a/frontend/src/components/organisms/TopNavigation/DrawerMobile.tsx +++ b/frontend/src/components/organisms/TopNavigation/DrawerMobile.tsx @@ -1,5 +1,4 @@ "use client"; -import React from "react"; import { Box, Grid, IconButton, SwipeableDrawer } from "@mui/material"; @@ -10,7 +9,7 @@ export const DrawerMobile = ({ setIsDrawerOpen, children, sx = {}, - rowGap = 4, + rowGap = 4 }) => { return ( setIsDrawerOpen(true)} open={isDrawerOpen} PaperProps={{ - sx: { width: "100%", ...sx }, + sx: { width: "100%", ...sx } }} > setIsDrawerOpen(false)}> diff --git a/frontend/src/components/organisms/VotesTable/VotesTableRow.tsx b/frontend/src/components/organisms/VotesTable/VotesTableRow.tsx index cdbe3723..3d154229 100644 --- a/frontend/src/components/organisms/VotesTable/VotesTableRow.tsx +++ b/frontend/src/components/organisms/VotesTable/VotesTableRow.tsx @@ -2,14 +2,11 @@ import { VotesTableI } from "@/lib/requests"; import { Button, OutlinedLightButton, Typography, VotePill } from "@atoms"; -import { customPalette, ICONS } from "@consts"; -import { useModal } from "@context"; +import { customPalette } from "@consts"; import { Card, TableDivider, UserAvatar, UserBasicInfo } from "@molecules"; import { Box, Grid } from "@mui/material"; -import { getProposalTypeLabel, truncateText } from "@utils"; +import { formatDisplayDate, getProposalTypeLabel, truncateText } from "@utils"; import { useTranslations } from "next-intl"; -import Image from "next/image"; -import { GovActionModalState } from "../types"; interface Props { votes: VotesTableI; @@ -25,25 +22,16 @@ export const VotesTableRow = ({ onActionClick }: Props) => { const t = useTranslations("LatestUpdates"); - const { openModal } = useModal(); const { user_name, user_address, user_photo_url, value, rationale_url, - gov_action_proposal_id, gov_action_proposal_title, - gov_action_proposal_type + gov_action_proposal_type, + vote_submit_time } = votes; - const openGAModal = () => { - openModal({ - type: "govActionModal", - state: { - id: gov_action_proposal_id - } - }); - }; return ( {t("govAction")} - - } - > + {gov_action_proposal_title ? truncateText(gov_action_proposal_title, 40) : t("notAvailable")} - + @@ -181,12 +156,39 @@ export const VotesTableRow = ({ > {t("voted")} - + + + + + + + {t("time")} + + + + {formatDisplayDate(vote_submit_time)} + + + + @@ -201,7 +203,7 @@ export const VotesTableRow = ({ > diff --git a/frontend/src/components/organisms/types.ts b/frontend/src/components/organisms/types.ts index b4ab0e0a..53a6beeb 100644 --- a/frontend/src/components/organisms/types.ts +++ b/frontend/src/components/organisms/types.ts @@ -95,10 +95,7 @@ export interface GovActionMetadata { } export interface OpenPreviewReasoningModal { - govAction: Pick< - GovernanceActionTableI, - "id" | "type" | "submit_time" | "end_time" | "tx_hash" - > & { + govAction: Partial & { vote?: Vote; vote_submit_time?: string; reasoning_title?: string; diff --git a/frontend/src/constants/forms.ts b/frontend/src/constants/forms.ts index 57d9c30b..6869c80d 100644 --- a/frontend/src/constants/forms.ts +++ b/frontend/src/constants/forms.ts @@ -8,29 +8,29 @@ import { isAdminRole, isSuperAdminRole } from "@/lib/utils/roles"; export const permissionsList: PermissionsListObject[] = [ { label: "Manage constitutional members", - value: "manage_cc_members", + value: "manage_cc_members" }, { label: "Upload Constitution version", - value: "add_constitution_version", - }, + value: "add_constitution_version" + } ]; //Roles that admin can append when creating new members through Admin Dashboard in application export const adminAddMemberRoleList: RoleListObject[] = [ { label: "Constitutional member", - value: "user", - }, + value: "user" + } ]; //Roles that super admin can append when creating new members through Admin Dashboard in application export const superAdminAddMemberRoleList: RoleListObject[] = [ { label: "Admin", - value: "admin", + value: "admin" }, - ...adminAddMemberRoleList, + ...adminAddMemberRoleList ]; //All roles available in application @@ -38,12 +38,12 @@ export const rolesList: RoleListObject[] = [ ...superAdminAddMemberRoleList, { label: "Super admin", - value: "super_admin", + value: "super_admin" }, { label: "Alumni", - value: "alumni", - }, + value: "alumni" + } ]; export const getRoleDropdownList = (userRole) => { @@ -57,5 +57,6 @@ export const getRoleDropdownList = (userRole) => { export const PROFILE_PICTURE_MAX_FILE_SIZE = 5; export const PATTERNS = { - hotAddress: /^[a-fA-F0-9]{56}$/, + username: /^[a-zA-Z0-9_|.\s]+$/, + hotAddress: /^[a-fA-F0-9]{56}$/ }; diff --git a/frontend/src/context/modal.tsx b/frontend/src/context/modal.tsx index 9dc72377..9b29b39d 100644 --- a/frontend/src/context/modal.tsx +++ b/frontend/src/context/modal.tsx @@ -43,8 +43,8 @@ export type ModalType = | "addReasoningModal" | "reasoningLinkModal" | "previewReasoningModal" - | "govActionModal" - | "switchUserStatus"; + | "switchUserStatus" + | "govActionModal"; const modals: Record = { none: { diff --git a/ipfs-service/src/bullmq/bullmq.module.ts b/ipfs-service/src/bullmq/bullmq.module.ts index a616bf14..3de0a31d 100644 --- a/ipfs-service/src/bullmq/bullmq.module.ts +++ b/ipfs-service/src/bullmq/bullmq.module.ts @@ -14,6 +14,11 @@ import { ExpressAdapter } from "@bull-board/express"; host: configService.getOrThrow("REDIS_HOST"), port: configService.getOrThrow("REDIS_PORT"), password: configService.getOrThrow("REDIS_PASSWORD"), + connectTimeout: 20000, + reconnectOnError: (err) => { + const targetErrors = ['READONLY', 'ETIMEDOUT', 'ECONNRESET']; + return targetErrors.some(targetError => err.message.includes(targetError)); + }, ...(configService.get('REDIS_TLS') === 'false' ? {} : { tls: {} }), }, }),