diff --git a/.gitignore b/.gitignore index 60ee619a1..3d712a194 100644 --- a/.gitignore +++ b/.gitignore @@ -120,6 +120,7 @@ local/ # used by haskell govtool/backend/dist-newstyle/ +govtool/backend/.stack-work/ # target environment config dir scripts/govtool/config/target diff --git a/CHANGELOG.md b/CHANGELOG.md index f9fea525b..6a4ce807a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ changes. ## [Unreleased] +- DRep metadata builder [Issue 497](https://github.com/IntersectMBO/govtool/issues/497) - Update Cardano Serialization Lib to 12.0.0-alpha.19 [Issue 521](https://github.com/IntersectMBO/govtool/issues/521) - Add generate jsonld function [Issue 451](https://github.com/IntersectMBO/govtool/issues/451) - Create GA review subbmision page [Issue 362](https://github.com/IntersectMBO/govtool/issues/362) @@ -26,6 +27,7 @@ changes. - Fix all the existing eslint errors [Issue 514](https://github.com/IntersectMBO/govtool/issues/514) - Fix all the existing typescript errors [Issue 514](https://github.com/IntersectMBO/govtool/issues/514) - Fix endless spinner on a dashboard [Issue 539](https://github.com/IntersectMBO/govtool/issues/539) +- Update frontend package readme to reflect recent changes [Issue 543](https://github.com/IntersectMBO/govtool/issues/543) ### Added @@ -59,6 +61,8 @@ changes. ### Changed +- `proposal/list` returns additional data such ass `expiryEpochNo`, `createdEpochNo`, `title`, `about`, `motivation`, + `rationale`. `TreasuryWithdrawals` GAs also got nicely formated details. [Issue 372](https://github.com/IntersectMBO/govtool/issues/372) - `drep/list` now return also `status` and `type` fields. Also it now returns the retired dreps, and you can search for given drep by name using optional query parameter. If the drep name is passed exactly, then you can even find a drep that's sole voter. [Issue 446](https://github.com/IntersectMBO/govtool/issues/446) - `drep/list` and `drep/info` endpoints now return additional data such as metadata url and hash, and voting power [Issue 223](https://github.com/IntersectMBO/govtool/issues/223) - `drep/info` now does not return sole voters (dreps without metadata) [Issue 317](https://github.com/IntersectMBO/govtool/issues/317) diff --git a/govtool/backend/Dockerfile.base b/govtool/backend/Dockerfile.base index e9b93f093..8f4e4c356 100644 --- a/govtool/backend/Dockerfile.base +++ b/govtool/backend/Dockerfile.base @@ -4,7 +4,7 @@ # is a common practice in Haskell projects, as it can significantly reduce the # time it takes to build the project. -FROM haskell:9.2-buster +FROM haskell:9.2.7-buster WORKDIR /src COPY . . RUN cabal update && cabal configure && cabal install --only-dependencies && rm -rf /src/* diff --git a/govtool/backend/app/Main.hs b/govtool/backend/app/Main.hs index 111a142ab..8de817ea3 100644 --- a/govtool/backend/app/Main.hs +++ b/govtool/backend/app/Main.hs @@ -80,7 +80,7 @@ import Data.Monoid (mempty) import qualified Data.Cache as Cache import VVA.API.Types import System.Clock (TimeSpec(TimeSpec)) -import Data.Pool (newPool, defaultPoolConfig) +import Data.Pool (createPool) import Database.PostgreSQL.Simple (connectPostgreSQL, close) import Data.Text.Encoding (encodeUtf8) import Data.Has (getter) @@ -138,7 +138,7 @@ startApp vvaConfig = do , dRepListCache , networkMetricsCache } - connectionPool <- newPool $ defaultPoolConfig (connectPostgreSQL (encodeUtf8 (dbSyncConnectionString $ getter vvaConfig))) close 1 60 + connectionPool <- createPool (connectPostgreSQL (encodeUtf8 (dbSyncConnectionString $ getter vvaConfig))) close 1 1 60 let appEnv = AppEnv {vvaConfig=vvaConfig, vvaCache=cacheEnv, vvaConnectionPool=connectionPool} server' <- mkVVAServer appEnv @@ -161,6 +161,8 @@ exceptionHandler vvaConfig mRequest exception = do (formatMessage mRequest exception) (recordUpdate mRequest exception) + + formatMessage :: Maybe Request -> SomeException -> String formatMessage Nothing exception = "Exception before request could be parsed: " ++ show exception formatMessage (Just request) exception = "Exception " ++ show exception ++ " while handling request " ++ show request diff --git a/govtool/backend/sql/list-proposals.sql b/govtool/backend/sql/list-proposals.sql index 5c8694134..94cd4849e 100644 --- a/govtool/backend/sql/list-proposals.sql +++ b/govtool/backend/sql/list-proposals.sql @@ -38,12 +38,27 @@ SELECT encode(creator_tx.hash, 'hex'), gov_action_proposal.index, gov_action_proposal.type::text, - gov_action_proposal.description::json, + ( + case when gov_action_proposal.type = 'TreasuryWithdrawals' then + json_build_object('Reward Address', stake_address.view, 'Amount', treasury_withdrawal.amount) + + when gov_action_proposal.type::text = 'InfoAction' then + json_build_object() + else + null + end + ) as description, epoch_utils.last_epoch_end_time + epoch_utils.epoch_duration *(gov_action_proposal.expiration - epoch_utils.last_epoch_no), + gov_action_proposal.expiration, creator_block.time, + creator_block.epoch_no, /* created date */ voting_anchor.url, encode(voting_anchor.data_hash, 'hex'), + off_chain_vote_data.title, + off_chain_vote_data.abstract, + off_chain_vote_data.motivation, + off_chain_vote_data.rationale, coalesce(Sum(ldd.amount) FILTER (WHERE voting_procedure.vote::text = 'Yes'), 0) +( CASE WHEN gov_action_proposal.type = 'NoConfidence' THEN always_no_confidence_voting_power.amount @@ -59,12 +74,18 @@ SELECT coalesce(Sum(ldd.amount) FILTER (WHERE voting_procedure.vote::text = 'Abstain'), 0) + always_abstain_voting_power.amount "abstain_votes" FROM gov_action_proposal + LEFT JOIN treasury_withdrawal + on gov_action_proposal.id = treasury_withdrawal.gov_action_proposal_id + LEFT JOIN stake_address + on stake_address.id = treasury_withdrawal.stake_address_id + CROSS JOIN EpochUtils AS epoch_utils CROSS JOIN always_no_confidence_voting_power CROSS JOIN always_abstain_voting_power JOIN tx AS creator_tx ON creator_tx.id = gov_action_proposal.tx_id JOIN block AS creator_block ON creator_block.id = creator_tx.block_id - JOIN voting_anchor ON voting_anchor.id = gov_action_proposal.voting_anchor_id + LEFT JOIN voting_anchor ON voting_anchor.id = gov_action_proposal.voting_anchor_id + LEFT JOIN off_chain_vote_data ON off_chain_vote_data.voting_anchor_id = voting_anchor.id LEFT JOIN voting_procedure ON voting_procedure.gov_action_proposal_id = gov_action_proposal.id LEFT JOIN LatestDrepDistr ldd ON ldd.hash_id = voting_procedure.drep_voter AND ldd.rn = 1 @@ -81,6 +102,13 @@ AND gov_action_proposal.expired_epoch IS NULL AND gov_action_proposal.dropped_epoch IS NULL GROUP BY (gov_action_proposal.id, + stake_address.view, + treasury_withdrawal.amount, + creator_block.epoch_no, + off_chain_vote_data.title, + off_chain_vote_data.abstract, + off_chain_vote_data.motivation, + off_chain_vote_data.rationale, gov_action_proposal.index, creator_tx.hash, creator_block.time, diff --git a/govtool/backend/src/VVA/API.hs b/govtool/backend/src/VVA/API.hs index c303fe32f..aba121ba6 100644 --- a/govtool/backend/src/VVA/API.hs +++ b/govtool/backend/src/VVA/API.hs @@ -116,11 +116,17 @@ proposalToResponse Types.Proposal {..} = proposalResponseTxHash = HexText proposalTxHash, proposalResponseIndex = proposalIndex, proposalResponseType = fromMaybe InfoAction $ readMaybe $ unpack proposalType, - proposalResponseDetails = GovernanceActionDetails proposalDetails, + proposalResponseDetails = GovernanceActionDetails <$> proposalDetails, proposalResponseExpiryDate = proposalExpiryDate, + proposalResponseExpiryEpochNo = proposalExpiryEpochNo, proposalResponseCreatedDate = proposalCreatedDate, + proposalResponseCreatedEpochNo = proposalCreatedEpochNo, proposalResponseUrl = proposalUrl, proposalResponseMetadataHash = HexText proposalDocHash, + proposalResponseTitle = proposalTitle, + proposalResponseAbout = proposalAbout, + proposalResponseMotivation = proposalMotivaiton, + proposalResponseRationale = proposalRationale, proposalResponseYesVotes = proposalYesVotes, proposalResponseNoVotes = proposalNoVotes, proposalResponseAbstainVotes = proposalAbstainVotes diff --git a/govtool/backend/src/VVA/API/Types.hs b/govtool/backend/src/VVA/API/Types.hs index efc79857d..5080cd339 100644 --- a/govtool/backend/src/VVA/API/Types.hs +++ b/govtool/backend/src/VVA/API/Types.hs @@ -238,11 +238,17 @@ data ProposalResponse = ProposalResponse proposalResponseTxHash :: HexText, proposalResponseIndex :: Integer, proposalResponseType :: GovernanceActionType, - proposalResponseDetails :: GovernanceActionDetails, + proposalResponseDetails :: Maybe GovernanceActionDetails, proposalResponseExpiryDate :: Maybe UTCTime, + proposalResponseExpiryEpochNo :: Maybe Integer, proposalResponseCreatedDate :: UTCTime, + proposalResponseCreatedEpochNo :: Integer, proposalResponseUrl :: Text, proposalResponseMetadataHash :: HexText, + proposalResponseTitle :: Maybe Text, + proposalResponseAbout :: Maybe Text, + proposalResponseMotivation :: Maybe Text, + proposalResponseRationale :: Maybe Text, proposalResponseYesVotes :: Integer, proposalResponseNoVotes :: Integer, proposalResponseAbstainVotes :: Integer @@ -258,9 +264,15 @@ exampleProposalResponse = "{ \"id\": \"proposalId123\"," <> "\"type\": \"InfoAction\"," <> "\"details\": \"some details\"," <> "\"expiryDate\": \"1970-01-01T00:00:00Z\"," + <> "\"expiryEpochNo\": 0," <> "\"createdDate\": \"1970-01-01T00:00:00Z\"," + <> "\"createdEpochNo\": 0," <> "\"url\": \"https://proposal.metadata.xyz\"," <> "\"metadataHash\": \"9af10e89979e51b8cdc827c963124a1ef4920d1253eef34a1d5cfe76438e3f11\"," + <> "\"title\": \"Proposal Title\"," + <> "\"about\": \"Proposal About\"," + <> "\"motivation\": \"Proposal Motivation\"," + <> "\"rationale\": \"Proposal Rationale\"," <> "\"yesVotes\": 0," <> "\"noVotes\": 0," <> "\"abstainVotes\": 0}" diff --git a/govtool/backend/src/VVA/Proposal.hs b/govtool/backend/src/VVA/Proposal.hs index d47e7af50..45980af7d 100644 --- a/govtool/backend/src/VVA/Proposal.hs +++ b/govtool/backend/src/VVA/Proposal.hs @@ -31,6 +31,9 @@ import VVA.Pool (ConnectionPool, withPool) import Control.Exception (throw) import VVA.Types (Proposal(..), AppError(..)) +import Data.Aeson +import Data.Aeson.Types (parseMaybe, Parser) +import Data.Text (Text) sqlFrom :: ByteString -> SQL.Query sqlFrom bs = fromString $ unpack $ Text.decodeUtf8 bs @@ -67,10 +70,46 @@ getProposals mProposalIds = withPool $ \conn -> do timeZone <- liftIO getCurrentTimeZone return $ map - ( \(id', txHash', index', type', details', expiryDate', createdDate', url', docHash', yesVotes', noVotes', abstainVotes') -> + ( \( id' + , txHash' + , index' + , type' + , details' + , expiryDate' + , expiryEpochNo' + , createdDate' + , createdEpochNo' + , url' + , docHash' + , title' + , about' + , motivation' + , rationale' + , yesVotes' + , noVotes' + , abstainVotes' + ) -> let eDate = localTimeToUTC timeZone <$> expiryDate' cDate = localTimeToUTC timeZone createdDate' in - Proposal id' txHash' (floor @Scientific index') type' details' eDate cDate url' docHash' (floor @Scientific yesVotes') (floor @Scientific noVotes') (floor @Scientific abstainVotes') + Proposal + id' + txHash' + (floor @Scientific index') + type' + details' + eDate + expiryEpochNo' + cDate + createdEpochNo' + url' + docHash' + title' + about' + motivation' + rationale' + (floor @Scientific yesVotes') + (floor @Scientific noVotes') + (floor @Scientific abstainVotes') ) - proposalResults + proposalResults \ No newline at end of file diff --git a/govtool/backend/src/VVA/Types.hs b/govtool/backend/src/VVA/Types.hs index e316f34e0..499bac20a 100644 --- a/govtool/backend/src/VVA/Types.hs +++ b/govtool/backend/src/VVA/Types.hs @@ -94,11 +94,17 @@ data Proposal = Proposal proposalTxHash :: Text, proposalIndex :: Integer, proposalType :: Text, - proposalDetails :: Value, + proposalDetails :: Maybe Value, proposalExpiryDate :: Maybe UTCTime, + proposalExpiryEpochNo :: Maybe Integer, proposalCreatedDate :: UTCTime, + proposalCreatedEpochNo :: Integer, proposalUrl :: Text, proposalDocHash :: Text, + proposalTitle :: Maybe Text, + proposalAbout :: Maybe Text, + proposalMotivaiton :: Maybe Text, + proposalRationale :: Maybe Text, proposalYesVotes :: Integer, proposalNoVotes :: Integer, proposalAbstainVotes :: Integer diff --git a/govtool/backend/stack.yaml b/govtool/backend/stack.yaml new file mode 100644 index 000000000..31940eb29 --- /dev/null +++ b/govtool/backend/stack.yaml @@ -0,0 +1,6 @@ +resolver: lts-20.24 +packages: + - . + +extra-deps: +- raven-haskell-0.1.4.1@sha256:9187272adc064197528645b5ad9b89163b668f386f34016d97fa646d5c790784 \ No newline at end of file diff --git a/govtool/backend/stack.yaml.lock b/govtool/backend/stack.yaml.lock new file mode 100644 index 000000000..985ab39a4 --- /dev/null +++ b/govtool/backend/stack.yaml.lock @@ -0,0 +1,19 @@ +# This file was autogenerated by Stack. +# You should not edit this file by hand. +# For more information, please see the documentation at: +# https://docs.haskellstack.org/en/stable/lock_files + +packages: +- completed: + hackage: raven-haskell-0.1.4.1@sha256:9187272adc064197528645b5ad9b89163b668f386f34016d97fa646d5c790784,1479 + pantry-tree: + sha256: e8f14bfed6b055dc95933257441ba97d3d779cbe08a0e82c3c2dff5d69c8c48f + size: 632 + original: + hackage: raven-haskell-0.1.4.1@sha256:9187272adc064197528645b5ad9b89163b668f386f34016d97fa646d5c790784 +snapshots: +- completed: + sha256: e019cd29e3f7f9dbad500225829a3f7a50f73c674614f2f452e21bb8bf5d99ea + size: 650253 + url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/20/24.yaml + original: lts-20.24 diff --git a/govtool/backend/vva-be.cabal b/govtool/backend/vva-be.cabal index e126e1aa2..2df658d4e 100644 --- a/govtool/backend/vva-be.cabal +++ b/govtool/backend/vva-be.cabal @@ -60,11 +60,13 @@ executable vva-be , lens , cache , clock - , resource-pool >= 0.4.0.0 + , resource-pool , postgresql-simple , data-has - , raven-haskell >= 0.1.4.1 , bytestring + , http-client + , http-client-tls + , raven-haskell >= 0.1.4.1 hs-source-dirs: app default-language: Haskell2010 @@ -97,6 +99,7 @@ library , resource-pool , swagger2 + exposed-modules: VVA.Config , VVA.CommandLine , VVA.API diff --git a/govtool/frontend/.eslintrc.cjs b/govtool/frontend/.eslintrc.cjs index 89a5aff94..07d27ff79 100644 --- a/govtool/frontend/.eslintrc.cjs +++ b/govtool/frontend/.eslintrc.cjs @@ -51,6 +51,7 @@ module.exports = { "operator-linebreak": "off", "implicit-arrow-linebreak": "off", "consistent-return": "off", + "no-console": ["error", { allow: ["warn", "error"] }], "no-shadow": "off", "function-paren-newline": "off", "object-curly-newline": "off", diff --git a/govtool/frontend/README.md b/govtool/frontend/README.md index ec8be6bdb..b66001800 100644 --- a/govtool/frontend/README.md +++ b/govtool/frontend/README.md @@ -3,7 +3,7 @@ Installed on your machine: 1. Node.js >= 18 ([official website](https://nodejs.org/en)) -2. npm or yarn - for package management +2. npm or yarn (recommended) - for package management Clone the project @@ -16,7 +16,7 @@ Fill .env based on env.example file Go to the project directory ```bash -cd voltaire-era/govtool/frontend +cd govtool/frontend ``` Install dependencies @@ -25,7 +25,7 @@ Install dependencies npm install ``` -or +or (recommended) ```bash yarn install @@ -37,7 +37,7 @@ Start the server npm run dev ``` -or +or (recommended) ```bash yarn dev @@ -59,12 +59,30 @@ yarn dev 10. Yup - ^1.3.2 11. Keen-Slider - ^6.8.5 12. Sentry - ^7.77.0 -13. Cardano serialization lib - 12.0.0-alpha.13 +13. Cardano serialization lib - 12.0.0-alpha.19 +14. i18next - ^23.7.19 + +### Code Quality and Checks Are Handled BY + +1. eslint - ^8.38.0 +2. vitest - ^1.1.0 +3. chromatic - ^10.0.0 ### Prerequisites -Install [`Git`](https://git-scm.com/) - version control -Recommendetd [`React developer tools`](https://react.dev/learn/react-developer-tools) +Install [`Git`](https://git-scm.com/) - version control. +Recommended [`React developer tools`](https://react.dev/learn/react-developer-tools). + +To automatically set correct node version: + +1. Install [`nvm`](https://github.com/nvm-sh/nvm) +2. Install `lts/hydrogen` version of node + +```bash + nvm install lts/hydrogen +``` + +3. Having that every time you enter the `govtool/frontend` package [`nvm`](https://github.com/nvm-sh/nvm) automatically sets the correct version of node. ## To Develop @@ -76,12 +94,24 @@ Recommendetd [`React developer tools`](https://react.dev/learn/react-developer-t npm install ``` +or (recommended) + +```bash +yarn install +``` + 2. Launch Server ```bash npm run dev ``` +or (recommended) + +```bash +yarn dev +``` + #### Using Nix and Direnv 1. Get [Nix](https://nixos.org/download). @@ -108,17 +138,26 @@ direnv allow yarn dev ``` +## After development + +Check our [Contributing Documentation](../../CONTRIBUTING.md) on how to submit a PR. + ### Users The GovTool application can read and display data from the Cardano chain using REST API. We distinguish two types of users: #### without a connected wallet who can: -1. see the governance actions along with their details and the number of votes + +1. See the governance actions along with their details and the number of votes + #### with connected wallet who can: -1. see the governance actions along with their details and the number of votes. -2. display the wallet status -3. delegate his or her voting power in a form of ADA to dReps, -4. register as DRrep -5. vote for the governance actions of his or her choice (if the user is registered) + +1. See the governance actions along with their details and the number of votes. +2. Display the wallet status. +3. Delegate his or her voting power in a form of ADA to dReps. +4. Register as DRrep or Sole Voter. +5. Vote for the Governance Actions of his or her choice (if the user is registered). +6. Create their own Governance Action. + diff --git a/govtool/frontend/public/icons/CopyBlueThin.svg b/govtool/frontend/public/icons/CopyBlueThin.svg new file mode 100644 index 000000000..2050c9abe --- /dev/null +++ b/govtool/frontend/public/icons/CopyBlueThin.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/govtool/frontend/public/icons/Share.svg b/govtool/frontend/public/icons/Share.svg new file mode 100644 index 000000000..a8b9eac2b --- /dev/null +++ b/govtool/frontend/public/icons/Share.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/govtool/frontend/src/App.tsx b/govtool/frontend/src/App.tsx index 7db190366..9e7b9300e 100644 --- a/govtool/frontend/src/App.tsx +++ b/govtool/frontend/src/App.tsx @@ -4,6 +4,7 @@ import { Route, Routes, useNavigate } from "react-router-dom"; import { Modal, ScrollToTop } from "@atoms"; import { PATHS } from "@consts"; import { useCardano, useModal } from "@context"; +import { useWalletConnectionListener } from "@hooks"; import { DashboardCards, DashboardGovernanceActions, @@ -11,28 +12,28 @@ import { } from "@organisms"; import { ChooseStakeKey, + CreateGovernanceAction, Dashboard, - ErrorPage, - Home, - GovernanceActions, + DashboardGovernanceActionsCategory, DelegateTodRep, - RegisterAsdRep, + ErrorPage, GovernanceActionDetails, - UpdatedRepMetadata, + GovernanceActions, GovernanceActionsCategory, - DashboardGovernanceActionsCategory, + Home, + RegisterAsdRep, + RegisterAsSoleVoter, + RetireAsDrep, RetireAsSoleVoter, + UpdatedRepMetadata, } from "@pages"; +import { SetupInterceptors } from "@services"; import { callAll, getItemFromLocalStorage, WALLET_LS_KEY, removeItemFromLocalStorage, } from "@utils"; -import { SetupInterceptors } from "./services"; -import { useWalletConnectionListener } from "./hooks"; -import { RegisterAsSoleVoter } from "./pages/RegisterAsSoleVoter"; -import { CreateGovernanceAction } from "./pages/CreateGovernanceAction"; export default () => { const { enable } = useCardano(); @@ -110,6 +111,7 @@ export default () => { /> } /> } /> + } /> } @@ -126,8 +128,8 @@ export default () => { handleClose={ !modals[modal.type].preventDismiss ? callAll(modals[modal.type]?.onClose, () => - openModal({ type: "none", state: null }), - ) + openModal({ type: "none", state: null }), + ) : undefined } > diff --git a/govtool/frontend/src/components/atoms/ClickOutside.tsx b/govtool/frontend/src/components/atoms/ClickOutside.tsx deleted file mode 100644 index 86266bf2a..000000000 --- a/govtool/frontend/src/components/atoms/ClickOutside.tsx +++ /dev/null @@ -1,30 +0,0 @@ -import React, { useRef, useEffect, RefObject } from "react"; - -const useOutsideClick = (ref: RefObject, onClick: () => void) => { - useEffect(() => { - document.addEventListener("mousedown", (e) => { - if (ref.current && !ref.current.contains(e.target as Node)) { - onClick(); - } - }); - - return () => { - document.removeEventListener("mousedown", (e) => { - if (ref.current && !ref.current.contains(e.target as Node)) { - onClick(); - } - }); - }; - }, [ref]); -}; - -interface Props { - children: React.ReactElement; - onClick: () => void; -} - -export const ClickOutside = ({ children, onClick }: Props) => { - const wrapperRef = useRef(null); - useOutsideClick(wrapperRef, onClick); - return
{children}
; -}; diff --git a/govtool/frontend/src/components/atoms/CopyButton.tsx b/govtool/frontend/src/components/atoms/CopyButton.tsx index 65601c718..021d5fcc0 100644 --- a/govtool/frontend/src/components/atoms/CopyButton.tsx +++ b/govtool/frontend/src/components/atoms/CopyButton.tsx @@ -4,11 +4,11 @@ import { ICONS } from "@consts"; import { useSnackbar } from "@context"; import { useTranslation } from "@hooks"; -interface Props { +type Props = { isChecked?: boolean; text: string; - variant?: string; -} + variant?: "blueThin" | "blue"; +}; export const CopyButton = ({ isChecked, text, variant }: Props) => { const { addSuccessAlert } = useSnackbar(); @@ -19,6 +19,10 @@ export const CopyButton = ({ isChecked, text, variant }: Props) => { return ICONS.copyBlueIcon; } + if (variant === "blueThin") { + return ICONS.copyBlueThinIcon; + } + if (isChecked) { return ICONS.copyWhiteIcon; } diff --git a/govtool/frontend/src/components/atoms/ExternalModalButton.tsx b/govtool/frontend/src/components/atoms/ExternalModalButton.tsx new file mode 100644 index 000000000..8584c15b0 --- /dev/null +++ b/govtool/frontend/src/components/atoms/ExternalModalButton.tsx @@ -0,0 +1,49 @@ +import { Typography } from "@mui/material"; + +import { Button } from "@atoms"; +import { ICONS } from "@consts"; +import { useModal } from "@context"; + +export const ExternalModalButton = ({ + label, + url, +}: { + label: string; + url: string; +}) => { + const { openModal } = useModal(); + + return ( + + ); +}; diff --git a/govtool/frontend/src/components/atoms/Radio.tsx b/govtool/frontend/src/components/atoms/Radio.tsx index 538fa7deb..d997c1b58 100644 --- a/govtool/frontend/src/components/atoms/Radio.tsx +++ b/govtool/frontend/src/components/atoms/Radio.tsx @@ -1,6 +1,9 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ -import { Box, Typography } from "@mui/material"; +import { Box } from "@mui/material"; + +import { Typography } from "@atoms"; import { UseFormRegister, UseFormSetValue } from "react-hook-form"; +import { theme } from "@/theme"; type RadioProps = { isChecked: boolean; @@ -10,11 +13,20 @@ type RadioProps = { setValue: UseFormSetValue; register: UseFormRegister; dataTestId?: string; + disabled?: boolean; }; export const Radio = ({ ...props }: RadioProps) => { - const { isChecked, name, setValue, title, value, dataTestId, register } = - props; + const { + isChecked, + name, + setValue, + title, + value, + dataTestId, + register, + disabled, + } = props; const handleClick = () => { setValue(name, value); @@ -23,13 +35,23 @@ export const Radio = ({ ...props }: RadioProps) => { return ( { + if (!disabled) handleClick(); + }} + borderRadius={isChecked ? "15px" : "12px"} + p={isChecked ? "2px" : 0} + border={isChecked ? 2 : 0} + borderColor={isChecked ? "specialCyanBorder" : undefined} + sx={[ + { + boxShadow: theme.shadows[1], + + "&:hover": { + color: "blue", + cursor: disabled ? "default" : "pointer", + }, + }, + ]} > { checked={isChecked} /> {title} diff --git a/govtool/frontend/src/components/atoms/Tooltip.tsx b/govtool/frontend/src/components/atoms/Tooltip.tsx index 4b8b7a90a..dd8d8dc23 100644 --- a/govtool/frontend/src/components/atoms/Tooltip.tsx +++ b/govtool/frontend/src/components/atoms/Tooltip.tsx @@ -1,12 +1,7 @@ import { styled } from "@mui/material"; import * as TooltipMUI from "@mui/material/Tooltip"; import Typography from "@mui/material/Typography"; - -type TooltipProps = Omit & { - heading?: string; - paragraphOne?: string; - paragraphTwo?: string; -}; +import { TooltipProps } from "@atoms"; const StyledTooltip = styled( ({ className, ...props }: TooltipMUI.TooltipProps) => ( diff --git a/govtool/frontend/src/components/atoms/VotePill.tsx b/govtool/frontend/src/components/atoms/VotePill.tsx index d28ed9da4..de29ac900 100644 --- a/govtool/frontend/src/components/atoms/VotePill.tsx +++ b/govtool/frontend/src/components/atoms/VotePill.tsx @@ -1,6 +1,7 @@ -import { Vote } from "@models"; import { Box, Typography } from "@mui/material"; +import { Vote } from "@models"; + export const VotePill = ({ vote, width, diff --git a/govtool/frontend/src/components/atoms/index.ts b/govtool/frontend/src/components/atoms/index.ts index 7072b7635..186752f80 100644 --- a/govtool/frontend/src/components/atoms/index.ts +++ b/govtool/frontend/src/components/atoms/index.ts @@ -2,9 +2,9 @@ export * from "./ActionRadio"; export * from "./Background"; export * from "./Button"; export * from "./Checkbox"; -export * from "./ClickOutside"; export * from "./CopyButton"; export * from "./DrawerLink"; +export * from "./ExternalModalButton"; export * from "./FormErrorMessage"; export * from "./FormHelpfulText"; export * from "./HighlightedText"; diff --git a/govtool/frontend/src/components/atoms/types.ts b/govtool/frontend/src/components/atoms/types.ts index 34f0fdf14..ff2e603b8 100644 --- a/govtool/frontend/src/components/atoms/types.ts +++ b/govtool/frontend/src/components/atoms/types.ts @@ -7,6 +7,7 @@ import { TextareaAutosizeProps, SxProps, } from "@mui/material"; +import * as TooltipMUI from "@mui/material/Tooltip"; export type ButtonProps = Omit & { size?: "small" | "medium" | "large" | "extraLarge"; @@ -71,3 +72,9 @@ export type InfoTextProps = { label: string; sx?: SxProps; }; + +export type TooltipProps = Omit & { + heading?: string; + paragraphOne?: string; + paragraphTwo?: string; +}; diff --git a/govtool/frontend/src/components/molecules/Breadcrumbs.tsx b/govtool/frontend/src/components/molecules/Breadcrumbs.tsx new file mode 100644 index 000000000..8a9e564a2 --- /dev/null +++ b/govtool/frontend/src/components/molecules/Breadcrumbs.tsx @@ -0,0 +1,62 @@ +import { NavLink, To } from "react-router-dom"; +import { Box } from "@mui/material"; +import Divider from "@mui/material/Divider"; + +import { useScreenDimension, useTranslation } from "@hooks"; +import { Typography } from "@atoms"; + +type BreadcrumbsProps = { + elementOne: string; + elementOnePath: To; + elementTwo: string; + isDataMissing: boolean; +}; + +export const Breadcrumbs = ({ + elementOne, + elementOnePath, + elementTwo, + isDataMissing, +}: BreadcrumbsProps) => { + const { t } = useTranslation(); + const { isMobile } = useScreenDimension(); + + return ( + + + + {elementOne} + + + + + {isDataMissing ? t("govActions.dataMissing") : elementTwo} + + + ); +}; diff --git a/govtool/frontend/src/components/molecules/DataActionsBar.tsx b/govtool/frontend/src/components/molecules/DataActionsBar.tsx index 86613a8bc..08e27a1db 100644 --- a/govtool/frontend/src/components/molecules/DataActionsBar.tsx +++ b/govtool/frontend/src/components/molecules/DataActionsBar.tsx @@ -2,10 +2,8 @@ import { Dispatch, FC, SetStateAction } from "react"; import { Box, InputBase } from "@mui/material"; import Search from "@mui/icons-material/Search"; -import { GovernanceActionsFilters, GovernanceActionsSorting } from "."; +import { GovernanceActionsFilters, GovernanceActionsSorting } from "@molecules"; import { OrderActionsChip } from "./OrderActionsChip"; -import { ClickOutside } from "../atoms"; - import { theme } from "@/theme"; type DataActionsBarProps = { @@ -50,7 +48,7 @@ export const DataActionsBar: FC = ({ ...props }) => { return ( <> - + setSearchText(e.target.value)} @@ -76,7 +74,7 @@ export const DataActionsBar: FC = ({ ...props }) => { fontWeight: 500, height: 48, padding: "16px 24px", - width: 231, + width: 500, }} /> = ({ ...props }) => { setSortOpen={setSortOpen} sortingActive={sortingActive} sortOpen={sortOpen} - /> + > + {filtersOpen && ( + + )} + {sortOpen && ( + + )} + - {filtersOpen && ( - - - - )} - {sortOpen && ( - - - - )} ); }; diff --git a/govtool/frontend/src/components/molecules/DataMissingInfoBox.tsx b/govtool/frontend/src/components/molecules/DataMissingInfoBox.tsx new file mode 100644 index 000000000..06830bdf5 --- /dev/null +++ b/govtool/frontend/src/components/molecules/DataMissingInfoBox.tsx @@ -0,0 +1,60 @@ +import { Box, Link } from "@mui/material"; + +import { Typography } from "@atoms"; +import { useTranslation } from "@hooks"; +import { openInNewTab } from "@utils"; + +export const DataMissingInfoBox = () => { + const { t } = useTranslation(); + + return ( + + + {/* TODO: Text to confirm/change */} + The data that was originally used when this Governance Action was + created has been formatted incorrectly. + + + {/* TODO: Text to confirm/change */} + GovTool uses external sources for Governance Action data, and these + sources are maintained by the proposers of the Actions. This error means + that GovTool cannot locate the data on the URL specified when the + Governance Action was originally posted. + + + // TODO: Add the correct link + openInNewTab( + "https://docs.sanchogov.tools/how-to-use-the-govtool/getting-started/get-a-compatible-wallet" + ) + } + sx={{ + fontFamily: "Poppins", + fontSize: "16px", + lineHeight: "24px", + cursor: "pointer", + }} + > + {t("learnMore")} + + + ); +}; diff --git a/govtool/frontend/src/components/molecules/GovernanceActionCard.tsx b/govtool/frontend/src/components/molecules/GovernanceActionCard.tsx index 567a3fb50..cbb17ac4b 100644 --- a/govtool/frontend/src/components/molecules/GovernanceActionCard.tsx +++ b/govtool/frontend/src/components/molecules/GovernanceActionCard.tsx @@ -1,35 +1,43 @@ import { FC } from "react"; import { Box } from "@mui/material"; -import InfoOutlinedIcon from "@mui/icons-material/InfoOutlined"; -import { Button, Typography, Tooltip } from "@atoms"; +import { Button } from "@atoms"; +import { + GovernanceActionCardElement, + GovernanceActionCardHeader, + GovernanceActionCardStatePill, + GovernanceActionsDatesBox, +} from "@molecules"; + import { useScreenDimension, useTranslation } from "@hooks"; import { formatDisplayDate, getFullGovActionId, getProposalTypeLabel, - getShortenedGovActionId, + getProposalTypeNoEmptySpaces, } from "@utils"; -import { theme } from "@/theme"; -interface ActionTypeProps - extends Omit< - ActionType, - | "yesVotes" - | "noVotes" - | "abstainVotes" - | "metadataHash" - | "url" - | "details" - | "id" - | "txHash" - | "index" - > { - onClick?: () => void; - inProgress?: boolean; +const mockedLongText = + "Lorem ipsum dolor sit, amet consectetur adipisicing elit. Sit, distinctio culpa minus eaque illo quidem voluptates quisquam mollitia consequuntur ex, sequi saepe? Ad ex adipisci molestiae sed."; + +type ActionTypeProps = Omit< + ActionType, + | "yesVotes" + | "noVotes" + | "abstainVotes" + | "metadataHash" + | "url" + | "details" + | "id" + | "txHash" + | "index" +> & { txHash: string; index: number; -} + isDataMissing: boolean; + onClick?: () => void; + inProgress?: boolean; +}; export const GovernanceActionCard: FC = ({ ...props }) => { const { @@ -40,193 +48,82 @@ export const GovernanceActionCard: FC = ({ ...props }) => { createdDate, txHash, index, + isDataMissing, } = props; const { isMobile, screenWidth } = useScreenDimension(); const { t } = useTranslation(); - const { - palette: { lightBlue }, - } = theme; - const govActionId = getFullGovActionId(txHash, index); - const proposalTypeNoEmptySpaces = getProposalTypeLabel(type).replace( - / /g, - "", - ); return ( - {inProgress && ( - - - {t("inProgress")} - - - )} + {inProgress && } - - - {t("govActions.governanceActionType")} - - - - - {getProposalTypeLabel(type)} - - - - - - - {t("govActions.governanceActionId")} - - - - - {getShortenedGovActionId(txHash, index)} - - - - + + + + + - {createdDate ? ( - - - {t("govActions.submissionDate")} - - - {formatDisplayDate(createdDate)} - - - - - - ) : null} - {expiryDate ? ( - - - {t("govActions.expiryDate")} - - - {formatDisplayDate(expiryDate)} - - - - - - ) : null} diff --git a/govtool/frontend/src/components/molecules/GovernanceActionCardElement.tsx b/govtool/frontend/src/components/molecules/GovernanceActionCardElement.tsx new file mode 100644 index 000000000..94517a9ca --- /dev/null +++ b/govtool/frontend/src/components/molecules/GovernanceActionCardElement.tsx @@ -0,0 +1,136 @@ +import { Box } from "@mui/material"; +import InfoOutlinedIcon from "@mui/icons-material/InfoOutlined"; + +import { Typography, Tooltip, CopyButton, TooltipProps } from "@atoms"; + +type BaseProps = { + label: string; + text: string; + dataTestId?: string; + isSliderCard?: boolean; + tooltipProps?: Omit; + marginBottom?: number; +}; + +type PillVariantProps = BaseProps & { + textVariant: "pill"; + isCopyButton?: false; +}; + +type OtherVariantsProps = BaseProps & { + textVariant?: "oneLine" | "twoLines" | "longText"; + isCopyButton?: boolean; +}; + +type GovernanceActionCardElementProps = PillVariantProps | OtherVariantsProps; + +export const GovernanceActionCardElement = ({ + label, + text, + dataTestId, + isSliderCard, + textVariant = "oneLine", + isCopyButton, + tooltipProps, + marginBottom, +}: GovernanceActionCardElementProps) => ( + + + + {label} + + {tooltipProps && ( + + + + )} + + + {textVariant === "pill" ? ( + + + {text} + + + ) : ( + + + {text} + + {isCopyButton && ( + + + + )} + + )} + + +); diff --git a/govtool/frontend/src/components/molecules/GovernanceActionCardHeader.tsx b/govtool/frontend/src/components/molecules/GovernanceActionCardHeader.tsx new file mode 100644 index 000000000..06314cea2 --- /dev/null +++ b/govtool/frontend/src/components/molecules/GovernanceActionCardHeader.tsx @@ -0,0 +1,60 @@ +import { Box } from "@mui/material"; +import InfoOutlinedIcon from "@mui/icons-material/InfoOutlined"; + +import { Tooltip, Typography } from "@atoms"; +import { useTranslation } from "@hooks"; + +type GovernanceActionCardHeaderProps = { + title: string; + isDataMissing: boolean; +}; + +export const GovernanceActionCardHeader = ({ + title, + isDataMissing, +}: GovernanceActionCardHeaderProps) => { + const { t } = useTranslation(); + + return ( + + + {isDataMissing ? t("govActions.dataMissing") : title} + + {isDataMissing && ( + + + + )} + + ); +}; diff --git a/govtool/frontend/src/components/molecules/GovernanceActionCardMyVote.tsx b/govtool/frontend/src/components/molecules/GovernanceActionCardMyVote.tsx new file mode 100644 index 000000000..c1dde83ec --- /dev/null +++ b/govtool/frontend/src/components/molecules/GovernanceActionCardMyVote.tsx @@ -0,0 +1,60 @@ +import { Box } from "@mui/material"; + +import { Button, Typography, VotePill } from "@atoms"; +import { openInNewTab } from "@utils"; +import { useTranslation } from "@hooks"; +import { Vote } from "@models"; + +type Props = { + vote: Vote; +}; + +export const GovernanceActionCardMyVote = ({ vote }: Props) => { + const { t } = useTranslation(); + + return ( + + + {t("govActions.myVote")} + + + + + + + + + ); +}; diff --git a/govtool/frontend/src/components/molecules/GovernanceActionCardStatePill.tsx b/govtool/frontend/src/components/molecules/GovernanceActionCardStatePill.tsx new file mode 100644 index 000000000..bba17071c --- /dev/null +++ b/govtool/frontend/src/components/molecules/GovernanceActionCardStatePill.tsx @@ -0,0 +1,51 @@ +import { Box } from "@mui/material"; +import CheckIcon from "@mui/icons-material/Check"; + +import { Typography } from "@atoms"; +import { useTranslation } from "@hooks"; + +export const GovernanceActionCardStatePill = ({ + variant = "voteSubmitted", +}: { + variant?: "inProgress" | "voteSubmitted"; +}) => { + const { t } = useTranslation(); + + return ( + + + {variant === "voteSubmitted" && ( + + )} + {variant === "inProgress" + ? t("inProgress") + : t("govActions.voteSubmitted")} + + + ); +}; diff --git a/govtool/frontend/src/components/molecules/GovernanceActionDetailsCardHeader.tsx b/govtool/frontend/src/components/molecules/GovernanceActionDetailsCardHeader.tsx new file mode 100644 index 000000000..5ba07c5c6 --- /dev/null +++ b/govtool/frontend/src/components/molecules/GovernanceActionDetailsCardHeader.tsx @@ -0,0 +1,57 @@ +import { useLocation } from "react-router-dom"; +import { Box } from "@mui/material"; + +import { Typography } from "@atoms"; +import { Share } from "@molecules"; +import { useTranslation } from "@hooks"; + +type GovernanceActionDetailsCardHeaderProps = { + title: string; + isDataMissing: boolean; +}; + +export const GovernanceActionDetailsCardHeader = ({ + title, + isDataMissing, +}: GovernanceActionDetailsCardHeaderProps) => { + const { t } = useTranslation(); + const { pathname, hash } = useLocation(); + + const govActionLinkToShare = `${window.location.protocol}//${ + window.location.hostname + }${window.location.port ? `:${window.location.port}` : ""}${pathname}${hash}`; + + return ( + + + + {isDataMissing ? t("govActions.dataMissing") : title} + + + + + ); +}; diff --git a/govtool/frontend/src/components/molecules/GovernanceActionDetailsCardLinks.tsx b/govtool/frontend/src/components/molecules/GovernanceActionDetailsCardLinks.tsx new file mode 100644 index 000000000..8028668be --- /dev/null +++ b/govtool/frontend/src/components/molecules/GovernanceActionDetailsCardLinks.tsx @@ -0,0 +1,58 @@ +import { Box } from "@mui/material"; + +import { Typography } from "@atoms"; +import { useScreenDimension, useTranslation } from "@hooks"; +import { LinkWithIcon } from "@molecules"; +import { openInNewTab } from "@/utils"; +import { ICONS } from "@/consts"; + +// TODO: When BE is ready, pass links as props +const LINKS = [ + "https://docs.sanchogov.tools/support/get-help-in-discord", + "https://docs.sanchogov.tools/how-to-use-the-govtool/prerequsites", + "https://docs.sanchogov.tools/faqs", + "https://docs.sanchogov.tools/", +]; + +export const GovernanceActionDetailsCardLinks = () => { + const { isMobile } = useScreenDimension(); + const { t } = useTranslation(); + + return ( + <> + + {t("govActions.supportingLinks")} + + + {LINKS.map((link) => ( + openInNewTab(link)} + icon={link} + cutWithEllipsis + /> + ))} + + + ); +}; diff --git a/govtool/frontend/src/components/molecules/GovernanceActionDetailsCardOnChainData.tsx b/govtool/frontend/src/components/molecules/GovernanceActionDetailsCardOnChainData.tsx new file mode 100644 index 000000000..e58aba1ed --- /dev/null +++ b/govtool/frontend/src/components/molecules/GovernanceActionDetailsCardOnChainData.tsx @@ -0,0 +1,79 @@ +import { Box } from "@mui/material"; + +import { Typography } from "@atoms"; +import { useTranslation } from "@hooks"; + +type GovernanceActionDetailsCardOnChainDataProps = { + data: { + label: string; + content: string; + }[]; +}; + +export const GovernanceActionDetailsCardOnChainData = ({ + data, +}: GovernanceActionDetailsCardOnChainDataProps) => { + const { t } = useTranslation(); + + return ( + + + + {t("govActions.onChainTransactionDetails")} + + + {data.map(({ label, content }) => ( + + + {label}: + + + {content} + + + ))} + + ); +}; diff --git a/govtool/frontend/src/components/molecules/GovernanceActionDetailsCardVotes.tsx b/govtool/frontend/src/components/molecules/GovernanceActionDetailsCardVotes.tsx new file mode 100644 index 000000000..2abf51ca9 --- /dev/null +++ b/govtool/frontend/src/components/molecules/GovernanceActionDetailsCardVotes.tsx @@ -0,0 +1,61 @@ +import { Dispatch, SetStateAction } from "react"; +import { Box } from "@mui/material"; + +import { useScreenDimension } from "@hooks"; +import { VoteActionForm, VotesSubmitted } from "@molecules"; + +type GovernanceActionCardVotesProps = { + setIsVoteSubmitted: Dispatch>; + abstainVotes: number; + noVotes: number; + yesVotes: number; + isOneColumn: boolean; + isVoter?: boolean; + voteFromEP?: string; + isDashboard?: boolean; + isInProgress?: boolean; +}; + +export const GovernanceActionDetailsCardVotes = ({ + setIsVoteSubmitted, + abstainVotes, + noVotes, + yesVotes, + isOneColumn, + isVoter, + voteFromEP, + isDashboard, + isInProgress, +}: GovernanceActionCardVotesProps) => { + const { screenWidth } = useScreenDimension(); + + const isModifiedPadding = + (isDashboard && screenWidth < 1368) ?? screenWidth < 1100; + + return ( + + {isVoter ? ( + + ) : ( + + )} + + ); +}; diff --git a/govtool/frontend/src/components/molecules/GovernanceActionsDatesBox.tsx b/govtool/frontend/src/components/molecules/GovernanceActionsDatesBox.tsx new file mode 100644 index 000000000..99065e13e --- /dev/null +++ b/govtool/frontend/src/components/molecules/GovernanceActionsDatesBox.tsx @@ -0,0 +1,126 @@ +import { Box } from "@mui/material"; +import InfoOutlinedIcon from "@mui/icons-material/InfoOutlined"; +import { Trans } from "react-i18next"; + +import { Tooltip, Typography } from "@atoms"; +import { useScreenDimension, useTranslation } from "@hooks"; + +type GovernanceActionsDatesBoxProps = { + createdDate: string; + expiryDate: string; + isSliderCard?: boolean; +}; + +export const GovernanceActionsDatesBox = ({ + createdDate, + expiryDate, + isSliderCard, +}: GovernanceActionsDatesBoxProps) => { + const { t } = useTranslation(); + const { screenWidth } = useScreenDimension(); + + const isFontSizeSmaller = screenWidth < 420; + + return ( + + + + , + , + ]} + /> + + + + + + + + , + , + ]} + /> + + + + + + + ); +}; diff --git a/govtool/frontend/src/components/molecules/GovernanceActionsFilters.tsx b/govtool/frontend/src/components/molecules/GovernanceActionsFilters.tsx index 05746f111..29bf5cc99 100644 --- a/govtool/frontend/src/components/molecules/GovernanceActionsFilters.tsx +++ b/govtool/frontend/src/components/molecules/GovernanceActionsFilters.tsx @@ -1,4 +1,4 @@ -import { Dispatch, SetStateAction, useCallback } from "react"; +import { Dispatch, SetStateAction, useCallback, useRef } from "react"; import { Box, Checkbox, @@ -8,16 +8,18 @@ import { } from "@mui/material"; import { GOVERNANCE_ACTIONS_FILTERS } from "@consts"; -import { useTranslation } from "@hooks"; +import { useOnClickOutside, useScreenDimension, useTranslation } from "@hooks"; interface Props { chosenFilters: string[]; setChosenFilters: Dispatch>; + closeFilters: () => void; } export const GovernanceActionsFilters = ({ chosenFilters, setChosenFilters, + closeFilters, }: Props) => { const handleFilterChange = useCallback( (e: React.ChangeEvent) => { @@ -36,6 +38,10 @@ export const GovernanceActionsFilters = ({ ); const { t } = useTranslation(); + const { isMobile, screenWidth } = useScreenDimension(); + + const wrapperRef = useRef(null); + useOnClickOutside(wrapperRef, closeFilters); return ( >; + closeSorts: () => void; } export const GovernanceActionsSorting = ({ chosenSorting, setChosenSorting, + closeSorts, }: Props) => { const { t } = useTranslation(); + const wrapperRef = useRef(null); + useOnClickOutside(wrapperRef, closeSorts); + return ( diff --git a/govtool/frontend/src/components/molecules/GovernanceVotedOnCard.tsx b/govtool/frontend/src/components/molecules/GovernanceVotedOnCard.tsx index 817c8495d..7e5a6aa2b 100644 --- a/govtool/frontend/src/components/molecules/GovernanceVotedOnCard.tsx +++ b/govtool/frontend/src/components/molecules/GovernanceVotedOnCard.tsx @@ -1,9 +1,7 @@ import { useNavigate } from "react-router-dom"; import { Box } from "@mui/material"; -import CheckIcon from "@mui/icons-material/Check"; -import InfoOutlinedIcon from "@mui/icons-material/InfoOutlined"; -import { Button, VotePill, Typography, Tooltip } from "@atoms"; +import { Button } from "@atoms"; import { PATHS } from "@consts"; import { useScreenDimension, useTranslation } from "@hooks"; import { VotedProposal } from "@models"; @@ -11,239 +9,114 @@ import { formatDisplayDate, getFullGovActionId, getProposalTypeLabel, - getShortenedGovActionId, - openInNewTab, + getProposalTypeNoEmptySpaces, } from "@utils"; -import { theme } from "@/theme"; +import { + GovernanceActionCardElement, + GovernanceActionCardHeader, + GovernanceActionCardMyVote, + GovernanceActionCardStatePill, + GovernanceActionsDatesBox, +} from "@molecules"; + +const mockedLongText = + "Lorem ipsum dolor sit, amet consectetur adipisicing elit. Sit, distinctio culpa minus eaque illo quidem voluptates quisquam mollitia consequuntur ex, sequi saepe? Ad ex adipisci molestiae sed."; -interface Props { +type Props = { votedProposal: VotedProposal; + isDataMissing: boolean; inProgress?: boolean; -} +}; -export const GovernanceVotedOnCard = ({ votedProposal, inProgress }: Props) => { +export const GovernanceVotedOnCard = ({ + votedProposal, + isDataMissing, + inProgress, +}: Props) => { const navigate = useNavigate(); const { proposal, vote } = votedProposal; - const { - palette: { lightBlue }, - } = theme; - const { isMobile } = useScreenDimension(); - const { t } = useTranslation(); - const proposalTypeNoEmptySpaces = getProposalTypeLabel(proposal.type).replace( - / /g, - "", - ); + const { isMobile, screenWidth } = useScreenDimension(); + const { t } = useTranslation(); return ( + - - {inProgress ? ( - t("inProgress") - ) : ( - <> - - {t("govActions.voteSubmitted")} - - )} - - - - - - {t("govActions.governanceActionType")} - - - - - {getProposalTypeLabel(proposal.type)} - - - - - - - {t("govActions.governanceActionId")} - - - - - {getShortenedGovActionId(proposal.txHash, proposal.index)} - - - - - - - {t("govActions.myVote")} - - - - - - - - + + + + + + - {proposal.createdDate ? ( - - - {t("govActions.submissionDate")} - - - {formatDisplayDate(proposal.createdDate)} - - - - - - ) : null} - {proposal.expiryDate ? ( - - - {t("govActions.expiryDate")} - - - {formatDisplayDate(proposal.expiryDate)} - - - - - - ) : null} diff --git a/govtool/frontend/src/components/molecules/LinkWithIcon.tsx b/govtool/frontend/src/components/molecules/LinkWithIcon.tsx index ab12e106c..ecfa97b16 100644 --- a/govtool/frontend/src/components/molecules/LinkWithIcon.tsx +++ b/govtool/frontend/src/components/molecules/LinkWithIcon.tsx @@ -10,6 +10,7 @@ export const LinkWithIcon = ({ onClick, icon, sx, + cutWithEllipsis, }: LinkWithIconProps) => ( {label} diff --git a/govtool/frontend/src/components/molecules/OrderActionsChip.tsx b/govtool/frontend/src/components/molecules/OrderActionsChip.tsx index ea1009154..006133653 100644 --- a/govtool/frontend/src/components/molecules/OrderActionsChip.tsx +++ b/govtool/frontend/src/components/molecules/OrderActionsChip.tsx @@ -1,23 +1,30 @@ import { Dispatch, SetStateAction } from "react"; -import { Box, Typography } from "@mui/material"; +import { Box } from "@mui/material"; +import { useScreenDimension, useTranslation } from "@hooks"; +import { Typography } from "@atoms"; import { ICONS } from "@consts"; import { theme } from "@/theme"; -interface Props { +type Props = { filtersOpen?: boolean; setFiltersOpen?: Dispatch>; chosenFiltersLength?: number; sortOpen: boolean; setSortOpen: Dispatch>; sortingActive: boolean; + children?: React.ReactNode; isFiltering?: boolean; -} +}; export const OrderActionsChip = (props: Props) => { + const { t } = useTranslation(); + const { isMobile } = useScreenDimension(); + const { palette: { secondary }, } = theme; + const { filtersOpen, setFiltersOpen = () => {}, @@ -26,33 +33,69 @@ export const OrderActionsChip = (props: Props) => { setSortOpen, sortingActive, isFiltering = true, + children, } = props; return ( - + {isFiltering && ( - + { + setSortOpen(false); + if (isFiltering) { + setFiltersOpen(!filtersOpen); + } + }} + data-testid="filters-button" + > filter { - setSortOpen(false); - if (isFiltering) { - setFiltersOpen(!filtersOpen); - } - }} src={filtersOpen ? ICONS.filterWhiteIcon : ICONS.filterIcon} style={{ - background: filtersOpen ? secondary.main : "transparent", borderRadius: "100%", - cursor: "pointer", - padding: "14px", + marginRight: "8px", overflow: "visible", height: 20, width: 20, objectFit: "contain", + ...(isMobile && { + background: filtersOpen ? secondary.main : "transparent", + padding: "14px", + marginRight: "0", + }), }} /> + {!isMobile && ( + + {t("filter")} + + )} {!filtersOpen && chosenFiltersLength > 0 && ( { height: "16px", justifyContent: "center", position: "absolute", - right: "0", + right: "-3px", top: "0", width: "16px", }} @@ -77,27 +120,54 @@ export const OrderActionsChip = (props: Props) => { )} )} - + { + if (isFiltering) { + setFiltersOpen(false); + } + setSortOpen(!sortOpen); + }} + data-testid="sort-button" + > sort { - if (isFiltering) { - setFiltersOpen(false); - } - setSortOpen(!sortOpen); - }} src={sortOpen ? ICONS.sortWhiteIcon : ICONS.sortIcon} style={{ - background: sortOpen ? secondary.main : "transparent", borderRadius: "100%", - cursor: "pointer", - padding: "14px", - height: 24, - width: 24, + marginRight: "8px", + height: 20, + width: 20, objectFit: "contain", + ...(isMobile && { + background: sortOpen ? secondary.main : "transparent", + padding: "14px", + marginRight: "0", + }), }} /> + {!isMobile && ( + + {t("sort")} + + )} {!sortOpen && sortingActive && ( { height: "16px", justifyContent: "center", position: "absolute", - right: "0", + right: "-3px", top: "0", width: "16px", }} @@ -119,6 +189,7 @@ export const OrderActionsChip = (props: Props) => { )} + {children} ); }; diff --git a/govtool/frontend/src/components/molecules/Share.tsx b/govtool/frontend/src/components/molecules/Share.tsx new file mode 100644 index 000000000..a57e7763d --- /dev/null +++ b/govtool/frontend/src/components/molecules/Share.tsx @@ -0,0 +1,97 @@ +import { useState } from "react"; +import { Box, Popover } from "@mui/material"; + +import { Typography } from "@atoms"; +import { ICONS } from "@consts"; +import { useSnackbar } from "@context"; +import { useTranslation } from "@hooks"; + +export const Share = ({ link }: { link: string }) => { + const { addSuccessAlert } = useSnackbar(); + const { t } = useTranslation(); + const [anchorEl, setAnchorEl] = useState(null); + + const handleClick = (e: React.MouseEvent) => { + setAnchorEl(e.currentTarget); + }; + + const handleClose = () => { + setAnchorEl(null); + }; + + const onCopy = (e: React.MouseEvent) => { + navigator.clipboard.writeText(link); + addSuccessAlert(t("alerts.copiedToClipboard")); + e.stopPropagation(); + }; + + const open = Boolean(anchorEl); + const id = open ? "simple-popover" : undefined; + + return ( + <> + + share icon + + + + {t("share")} + + link + + {t("clickToCopyLink")} + + + + ); +}; diff --git a/govtool/frontend/src/components/molecules/SliderArrow.tsx b/govtool/frontend/src/components/molecules/SliderArrow.tsx new file mode 100644 index 000000000..b4b079d48 --- /dev/null +++ b/govtool/frontend/src/components/molecules/SliderArrow.tsx @@ -0,0 +1,45 @@ +import { Box } from "@mui/material"; +import ChevronRightIcon from "@mui/icons-material/ChevronRight"; + +import { theme } from "@/theme"; + +type SliderArrowProps = { + disabled: boolean; + onClick: (e: React.MouseEvent) => void; + left?: boolean; +}; + +export const SliderArrow = ({ disabled, onClick, left }: SliderArrowProps) => { + const { + palette: { primaryBlue, arcticWhite, lightBlue }, + } = theme; + + return ( + + + + ); +}; diff --git a/govtool/frontend/src/components/molecules/SliderArrows.tsx b/govtool/frontend/src/components/molecules/SliderArrows.tsx new file mode 100644 index 000000000..6d5f9e7a6 --- /dev/null +++ b/govtool/frontend/src/components/molecules/SliderArrows.tsx @@ -0,0 +1,46 @@ +import { KeenSliderHooks, KeenSliderInstance } from "keen-slider/react"; +import { SliderArrow } from "@molecules"; +import { Box } from "@mui/material"; + +type SliderArrowsProps = { + currentSlide: number; + instanceRef: React.MutableRefObject | null>; + itemsPerView: number; +}; + +export const SliderArrows = ({ + currentSlide, + instanceRef, + itemsPerView, +}: SliderArrowsProps) => + instanceRef.current && ( + + ) => { + e.stopPropagation(); + instanceRef.current?.prev(); + }} + disabled={currentSlide === 0} + /> + ) => { + e.stopPropagation(); + instanceRef.current?.next(); + }} + disabled={ + currentSlide + itemsPerView >= + instanceRef.current.track.details.slides.length + } + /> + + ); diff --git a/govtool/frontend/src/components/molecules/VoteActionForm.tsx b/govtool/frontend/src/components/molecules/VoteActionForm.tsx index 4c7413400..5222bea75 100644 --- a/govtool/frontend/src/components/molecules/VoteActionForm.tsx +++ b/govtool/frontend/src/components/molecules/VoteActionForm.tsx @@ -1,4 +1,11 @@ -import { useState, useEffect, useMemo, useCallback } from "react"; +import { + useState, + useEffect, + useMemo, + useCallback, + Dispatch, + SetStateAction, +} from "react"; import { useLocation } from "react-router-dom"; import { Box, Link } from "@mui/material"; @@ -13,22 +20,34 @@ import { } from "@hooks"; import { openInNewTab } from "@utils"; +import { Trans } from "react-i18next"; import { ControlledField } from "../organisms"; +// TODO: Decide with BE on how cast votes will be implemented +// and adjust accordingly the component below (UI is ready). +const castVoteDate = undefined; +const castVoteChangeDeadline = "20.06.2024 (Epoch 445)"; + +type VoteActionFormProps = { + setIsVoteSubmitted: Dispatch>; + voteFromEP?: string; + yesVotes: number; + noVotes: number; + abstainVotes: number; + isInProgress?: boolean; +}; + export const VoteActionForm = ({ + setIsVoteSubmitted, voteFromEP, yesVotes, noVotes, abstainVotes, -}: { - voteFromEP?: string; - yesVotes: number; - noVotes: number; - abstainVotes: number; -}) => { - const { state } = useLocation(); + isInProgress, +}: VoteActionFormProps) => { const [isContext, setIsContext] = useState(false); - const { isMobile, screenWidth } = useScreenDimension(); + const { state } = useLocation(); + const { isMobile } = useScreenDimension(); const { openModal } = useModal(); const { t } = useTranslation(); const { voter } = useGetVoterInfo(); @@ -49,8 +68,10 @@ export const VoteActionForm = ({ useEffect(() => { if (state && state.vote) { setValue("vote", state.vote); + setIsVoteSubmitted(true); } else if (voteFromEP) { setValue("vote", voteFromEP); + setIsVoteSubmitted(true); } }, [state, voteFromEP, setValue]); @@ -79,81 +100,124 @@ export const VoteActionForm = ({ [state], ); - const renderChangeVoteButton = useMemo(() => ( - - {t('govActions.changeVote')} - - ), + const renderChangeVoteButton = useMemo( + () => ( + + {t("govActions.changeVote")} + + ), [confirmVote, areFormErrors, vote, isVoteLoading], ); return ( - - - - {t("govActions.chooseHowToVote")} - - - - - - - - - - + + + {castVoteDate ? ( + <> + + ]} + /> + + + {t("govActions.castVoteDeadline", { + date: castVoteChangeDeadline, + })} + + + ) : ( + + {t("govActions.chooseHowToVote")} + + )} + + + + {(voter?.isRegisteredAsDRep || voter?.isRegisteredAsSoleVoter) && ( )} + {/* TODO: Change below into new voting context */}

{isContext && ( - + - @@ -228,7 +300,8 @@ export const VoteActionForm = ({ "https://docs.sanchogov.tools/faqs/how-to-create-a-metadata-anchor", ) } - mb={isMobile ? 2 : 8} + mt="12px" + mb={isMobile ? 2 : 6} sx={{ cursor: "pointer" }} textAlign="center" visibility={!isContext ? "hidden" : "visible"} @@ -251,16 +324,16 @@ export const VoteActionForm = ({ {t("govActions.selectDifferentOption")} {(state?.vote && state?.vote !== vote) || - (voteFromEP && voteFromEP !== vote) ? ( - - {isMobile ? renderChangeVoteButton : renderCancelButton} - - {isMobile ? renderCancelButton : renderChangeVoteButton} - + (voteFromEP && voteFromEP !== vote) ? ( + + {isMobile ? renderChangeVoteButton : renderCancelButton} + + {isMobile ? renderCancelButton : renderChangeVoteButton} + ) : ( { - const { - palette: { lightBlue }, - } = theme; - const { isMobile } = useScreenDimension(); const { t } = useTranslation(); return ( @@ -31,68 +26,66 @@ export const VotesSubmitted = ({ yesVotes, noVotes, abstainVotes }: Props) => { src={IMAGES.govActionListImage} width="64px" height="64px" - style={{ marginBottom: "10px" }} + style={{ marginBottom: "24px" }} /> - + {t("govActions.voteSubmitted")} - - {t("govActions.forGovAction")} - - - {t("govActions.votesSubmittedOnChain")} - - {t("govActions.votes")} + {t("govActions.forGovAction")} + + + {t("govActions.votesSubmittedOnChain")} - + ₳ {correctAdaFormat(yesVotes)} - + ₳ {correctAdaFormat(abstainVotes)} - + ₳ {correctAdaFormat(noVotes)} diff --git a/govtool/frontend/src/components/molecules/index.ts b/govtool/frontend/src/components/molecules/index.ts index b87a802df..78d4f0563 100644 --- a/govtool/frontend/src/components/molecules/index.ts +++ b/govtool/frontend/src/components/molecules/index.ts @@ -1,18 +1,32 @@ export * from "./ActionCard"; +export * from "./Breadcrumbs"; export * from "./Card"; export * from "./CenteredBoxBottomButtons"; export * from "./CenteredBoxPageWrapper"; export * from "./DashboardActionCard"; export * from "./DataActionsBar"; +export * from "./DataMissingInfoBox"; export * from "./DRepInfoCard"; export * from "./Field"; export * from "./GovActionDetails"; export * from "./GovernanceActionCard"; +export * from "./GovernanceActionCardElement"; +export * from "./GovernanceActionCardHeader"; +export * from "./GovernanceActionDetailsCardLinks"; +export * from "./GovernanceActionCardMyVote"; +export * from "./GovernanceActionCardStatePill"; +export * from "./GovernanceActionDetailsCardVotes"; +export * from "./GovernanceActionDetailsCardHeader"; +export * from "./GovernanceActionDetailsCardOnChainData"; +export * from "./GovernanceActionsDatesBox"; export * from "./GovernanceActionsFilters"; export * from "./GovernanceActionsSorting"; export * from "./GovernanceVotedOnCard"; export * from "./LinkWithIcon"; export * from "./OrderActionsChip"; +export * from "./Share"; +export * from "./SliderArrow"; +export * from "./SliderArrows"; export * from "./Step"; export * from "./VoteActionForm"; export * from "./VotesSubmitted"; diff --git a/govtool/frontend/src/components/molecules/types.ts b/govtool/frontend/src/components/molecules/types.ts index 0ed7df185..dbe0db33c 100644 --- a/govtool/frontend/src/components/molecules/types.ts +++ b/govtool/frontend/src/components/molecules/types.ts @@ -5,6 +5,7 @@ export type LinkWithIconProps = { onClick: () => void; icon?: JSX.Element; sx?: SxProps; + cutWithEllipsis?: boolean; }; export type StepProps = { diff --git a/govtool/frontend/src/components/organisms/CreateGovernanceActionSteps/StorageInformation.tsx b/govtool/frontend/src/components/organisms/CreateGovernanceActionSteps/StorageInformation.tsx index 55cd6d46f..015ae75d1 100644 --- a/govtool/frontend/src/components/organisms/CreateGovernanceActionSteps/StorageInformation.tsx +++ b/govtool/frontend/src/components/organisms/CreateGovernanceActionSteps/StorageInformation.tsx @@ -37,7 +37,7 @@ export const StorageInformation = ({ setStep }: StorageInformationProps) => { const openGuideAboutStoringInformation = () => openInNewTab("https://sancho.network/"); - const isActionButtonDisabled = !watch("storingURL"); + const isActionButtonDisabled = !watch("storingURL") || !!errors.storingURL; const onClickBack = () => setStep(5); diff --git a/govtool/frontend/src/components/organisms/DashboardCards.tsx b/govtool/frontend/src/components/organisms/DashboardCards.tsx index fd684fd6b..98a99630d 100644 --- a/govtool/frontend/src/components/organisms/DashboardCards.tsx +++ b/govtool/frontend/src/components/organisms/DashboardCards.tsx @@ -1,10 +1,10 @@ -import { useCallback, useMemo, useState } from "react"; +import { useCallback, useMemo } from "react"; import { useNavigate } from "react-router-dom"; import { Box, CircularProgress } from "@mui/material"; import { Trans } from "react-i18next"; import { IMAGES, PATHS } from "@consts"; -import { useCardano, useModal } from "@context"; +import { useCardano } from "@context"; import { useGetAdaHolderVotingPowerQuery, useScreenDimension, @@ -17,8 +17,6 @@ import { correctAdaFormat, formHexToBech32, openInNewTab } from "@utils"; export const DashboardCards = () => { const { - buildDRepRetirementCert, - buildSignSubmitConwayCertTx, dRepID, dRepIDBech32, isPendingTransaction, @@ -28,67 +26,10 @@ export const DashboardCards = () => { const navigate = useNavigate(); const { currentDelegation } = useGetAdaHolderCurrentDelegationQuery(stakeKey); const { screenWidth } = useScreenDimension(); - const { openModal } = useModal(); - const [isRetirementLoading, setIsRetirementLoading] = - useState(false); const { votingPower } = useGetAdaHolderVotingPowerQuery(stakeKey); const { t } = useTranslation(); const { voter } = useGetVoterInfo(); - const retireAsDrep = useCallback(async () => { - try { - setIsRetirementLoading(true); - const isPendingTx = isPendingTransaction(); - - if (isPendingTx) return; - if (!voter?.deposit) throw new Error("Can not get deposit"); - - const certBuilder = await buildDRepRetirementCert( - voter.deposit.toString(), - ); - const result = await buildSignSubmitConwayCertTx({ - certBuilder, - type: "retireAsDrep", - voterDeposit: voter.deposit.toString(), - }); - if (result) { - openModal({ - type: "statusModal", - state: { - status: "success", - title: t("modals.retirement.title"), - message: t("modals.retirement.message"), - link: `https://adanordic.com/latest_transactions`, - buttonText: t("modals.common.goToDashboard"), - dataTestId: "retirement-transaction-submitted-modal", - }, - }); - } - // eslint-disable-next-line @typescript-eslint/no-explicit-any - } catch (error: any) { - const errorMessage = error.info ? error.info : error; - - openModal({ - type: "statusModal", - state: { - status: "warning", - message: errorMessage, - buttonText: t("modals.common.goToDashboard"), - title: t("modals.common.oops"), - dataTestId: "retirement-transaction-error-modal", - }, - }); - } finally { - setIsRetirementLoading(false); - } - }, [ - buildDRepRetirementCert, - buildSignSubmitConwayCertTx, - isPendingTransaction, - openModal, - voter?.deposit, - ]); - const delegationDescription = useMemo(() => { const correctAdaRepresentation = correctAdaFormat(votingPower); if (currentDelegation === dRepID) { @@ -416,12 +357,13 @@ export const DashboardCards = () => { : "register-learn-more-button" } description={registrationCardDescription} - firstButtonAction={ - voter?.isRegisteredAsDRep - ? retireAsDrep - : () => navigateTo(PATHS.registerAsdRep) + firstButtonAction={() => + navigateTo( + voter?.isRegisteredAsDRep + ? PATHS.retireAsDrep + : PATHS.registerAsdRep, + ) } - firstButtonIsLoading={isRetirementLoading} firstButtonLabel={ pendingTransaction.registerAsDrep || pendingTransaction.retireAsDrep ? "" diff --git a/govtool/frontend/src/components/organisms/DashboardGovernanceActionDetails.tsx b/govtool/frontend/src/components/organisms/DashboardGovernanceActionDetails.tsx index 586005b07..480de270c 100644 --- a/govtool/frontend/src/components/organisms/DashboardGovernanceActionDetails.tsx +++ b/govtool/frontend/src/components/organisms/DashboardGovernanceActionDetails.tsx @@ -1,17 +1,10 @@ import { useNavigate, useLocation, - NavLink, useParams, generatePath, } from "react-router-dom"; -import { - Box, - Breadcrumbs, - CircularProgress, - Link, - Typography, -} from "@mui/material"; +import { Box, CircularProgress, Link, Typography } from "@mui/material"; import { ICONS, PATHS } from "@consts"; import { @@ -20,18 +13,24 @@ import { useScreenDimension, useTranslation, } from "@hooks"; -import { GovernanceActionDetailsCard } from "@organisms"; import { formatDisplayDate, getShortenedGovActionId, getProposalTypeLabel, } from "@utils"; +import { GovernanceActionDetailsCard } from "@organisms"; +import { Breadcrumbs } from "@molecules"; +import { useCardano } from "@/context"; + +// TODO: Remove when data validation is ready +const isDataMissing = false; export const DashboardGovernanceActionDetails = () => { const { voter } = useGetVoterInfo(); + const { pendingTransaction } = useCardano(); const { state, hash } = useLocation(); const navigate = useNavigate(); - const { isMobile, screenWidth } = useScreenDimension(); + const { isMobile } = useScreenDimension(); const { t } = useTranslation(); const { proposalId } = useParams(); const fullProposalId = proposalId + hash; @@ -43,21 +42,6 @@ export const DashboardGovernanceActionDetails = () => { state ? state.index : data?.proposal.index ?? "", ); - const breadcrumbs = [ - - - {t("govActions.title")} - - , - - {t("govActions.voteOnGovActions")} - , - ]; - return ( { flex={1} > - {breadcrumbs} - + elementOne={t("govActions.title")} + elementOnePath={PATHS.dashboardGovernanceActions} + elementTwo="Fund our project" + isDataMissing={false} + /> { style={{ marginRight: "12px", transform: "rotate(180deg)" }} /> - {t("backToList")} + {t("back")} @@ -128,23 +108,32 @@ export const DashboardGovernanceActionDetails = () => { ? formatDisplayDate(state.createdDate) : formatDisplayDate(data.proposal.createdDate) } - details={state ? state.details : data.proposal.details} + // TODO: Add data validation + isDataMissing={isDataMissing} expiryDate={ state ? formatDisplayDate(state.expiryDate) : formatDisplayDate(data.proposal.expiryDate) } - isDRep={voter?.isRegisteredAsDRep || voter?.isRegisteredAsSoleVoter} + isVoter={ + voter?.isRegisteredAsDRep || voter?.isRegisteredAsSoleVoter + } noVotes={state ? state.noVotes : data.proposal.noVotes} type={ state ? getProposalTypeLabel(state.type) : getProposalTypeLabel(data.proposal.type) } - url={state ? state.url : data.proposal.url} + // TODO: To decide if we want to keep it when metadate BE is ready + // url={state ? state.url : data.proposal.url} yesVotes={state ? state.yesVotes : data.proposal.yesVotes} voteFromEP={data?.vote?.vote} - shortenedGovActionId={shortenedGovActionId} + govActionId={fullProposalId} + isInProgress={ + pendingTransaction.vote?.resourceId === + fullProposalId.replace("#", "") + } + isDashboard /> ) : ( diff --git a/govtool/frontend/src/components/organisms/DashboardGovernanceActions.tsx b/govtool/frontend/src/components/organisms/DashboardGovernanceActions.tsx index d865e5e8d..f9b22bc1e 100644 --- a/govtool/frontend/src/components/organisms/DashboardGovernanceActions.tsx +++ b/govtool/frontend/src/components/organisms/DashboardGovernanceActions.tsx @@ -2,25 +2,25 @@ import { useState, useCallback, useEffect } from "react"; import { Box, CircularProgress, Tab, Tabs, styled } from "@mui/material"; import { useLocation } from "react-router-dom"; -import { GOVERNANCE_ACTIONS_FILTERS } from '@consts'; -import { useCardano } from '@context'; +import { GOVERNANCE_ACTIONS_FILTERS } from "@consts"; +import { useCardano } from "@context"; import { useGetProposalsQuery, useGetVoterInfo, useScreenDimension, useTranslation, -} from '@hooks'; -import { DataActionsBar } from '@molecules'; +} from "@hooks"; +import { DataActionsBar } from "@molecules"; import { GovernanceActionsToVote, DashboardGovernanceActionsVotedOn, -} from '@organisms'; +} from "@organisms"; -interface TabPanelProps { +type TabPanelProps = { children?: React.ReactNode; index: number; value: number; -} +}; const defaultCategories = GOVERNANCE_ACTIONS_FILTERS.map( (category) => category.key, @@ -36,8 +36,8 @@ const CustomTabPanel = (props: TabPanelProps) => { id={`simple-tabpanel-${index}`} aria-labelledby={`simple-tab-${index}`} style={{ - display: 'flex', - flexDirection: 'column', + display: "flex", + flexDirection: "column", flex: value !== index ? 0 : 1, }} > @@ -53,22 +53,22 @@ type StyledTabProps = { const StyledTab = styled((props: StyledTabProps) => ( ))(() => ({ - textTransform: 'none', + textTransform: "none", fontWeight: 400, fontSize: 16, - color: '#242232', - '&.Mui-selected': { - color: '#FF640A', + color: "#242232", + "&.Mui-selected": { + color: "#FF640A", fontWeight: 500, }, })); export const DashboardGovernanceActions = () => { - const [searchText, setSearchText] = useState(''); + const [searchText, setSearchText] = useState(""); const [filtersOpen, setFiltersOpen] = useState(false); const [chosenFilters, setChosenFilters] = useState([]); const [sortOpen, setSortOpen] = useState(false); - const [chosenSorting, setChosenSorting] = useState(''); + const [chosenSorting, setChosenSorting] = useState(""); const { voter } = useGetVoterInfo(); const { isMobile } = useScreenDimension(); const { t } = useTranslation(); @@ -145,7 +145,7 @@ export const DashboardGovernanceActions = () => { { > diff --git a/govtool/frontend/src/components/organisms/DashboardGovernanceActionsVotedOn.tsx b/govtool/frontend/src/components/organisms/DashboardGovernanceActionsVotedOn.tsx index e2b024610..5f8758cd2 100644 --- a/govtool/frontend/src/components/organisms/DashboardGovernanceActionsVotedOn.tsx +++ b/govtool/frontend/src/components/organisms/DashboardGovernanceActionsVotedOn.tsx @@ -1,22 +1,22 @@ -import { useMemo } from 'react'; -import { Box, Typography, CircularProgress } from '@mui/material'; +import { useMemo } from "react"; +import { Box, Typography, CircularProgress } from "@mui/material"; -import { GovernanceVotedOnCard } from '@molecules'; +import { GovernanceVotedOnCard } from "@molecules"; import { useGetDRepVotesQuery, useScreenDimension, useTranslation, -} from '@hooks'; -import { Slider } from '.'; -import { getProposalTypeLabel } from '@/utils/getProposalTypeLabel'; -import { getFullGovActionId } from '@/utils'; -import { useCardano } from '@/context'; +} from "@hooks"; +import { Slider } from "@organisms"; +import { getProposalTypeLabel } from "@/utils/getProposalTypeLabel"; +import { getFullGovActionId } from "@/utils"; +import { useCardano } from "@/context"; -interface DashboardGovernanceActionsVotedOnProps { +type DashboardGovernanceActionsVotedOnProps = { filters: string[]; searchPhrase?: string; sorting: string; -} +}; export const DashboardGovernanceActionsVotedOn = ({ filters, @@ -52,11 +52,11 @@ export const DashboardGovernanceActionsVotedOn = ({ <> {!data.length ? ( - {t('govActions.youHaventVotedYet')} + {t("govActions.youHaventVotedYet")} ) : !filteredData?.length ? ( - {t('govActions.noResultsForTheSearch')} + {t("govActions.noResultsForTheSearch")} ) : ( <> @@ -64,10 +64,11 @@ export const DashboardGovernanceActionsVotedOn = ({

(
{ - const { screenWidth } = useScreenDimension(); - const { openModal } = useModal(); - const { t } = useTranslation(); + const [isVoteSubmitted, setIsVoteSubmitted] = useState(false); + const { screenWidth, isMobile } = useScreenDimension(); + + const isOneColumn = (isDashboard && screenWidth < 1036) ?? isMobile; return ( - - - - - {t("govActions.submissionDate")} - - - {createdDate} - - - - - - - - {t("govActions.expiryDate")} - - - {expiryDate} - - - - - - - - - - {t("govActions.governanceActionType")} - - - - {type} - - - - - - {t("govActions.governanceActionId")} - - - - - {shortenedGovActionId} - - - - - - - {t("govActions.details")} - - - - {JSON.stringify(details, null, 1)} - - - - - - - - {isDRep ? ( - - ) : ( - - )} - + {(isVoteSubmitted || isInProgress) && ( + + )} + + ); }; diff --git a/govtool/frontend/src/components/organisms/GovernanceActionDetailsCardData.tsx b/govtool/frontend/src/components/organisms/GovernanceActionDetailsCardData.tsx new file mode 100644 index 000000000..9a6641d41 --- /dev/null +++ b/govtool/frontend/src/components/organisms/GovernanceActionDetailsCardData.tsx @@ -0,0 +1,131 @@ +import { Box } from "@mui/material"; + +import { ExternalModalButton } from "@atoms"; +import { + GovernanceActionCardElement, + GovernanceActionDetailsCardLinks, + DataMissingInfoBox, + GovernanceActionDetailsCardHeader, + GovernanceActionsDatesBox, + GovernanceActionDetailsCardOnChainData, +} from "@molecules"; +import { useScreenDimension, useTranslation } from "@hooks"; +import { getProposalTypeNoEmptySpaces } from "@utils"; + +const mockedLongDescription = + "I am the Cardano crusader carving his path in the blockchain battleground. With a mind sharper than a Ledger Nano X, this fearless crypto connoisseur fearlessly navigates the volatile seas of Cardano, turning code into currency. Armed with a keyboard and a heart pumping with blockchain beats, Mister Big Bad fearlessly champions decentralization, smart contracts, and the Cardano community. His Twitter feed is a mix of market analysis that rivals CNBC and memes that could break the internet."; + +const mockedOnChainData = [ + { + label: "Reward Address", + content: "Lorem ipsum dolor sit amet consectetur.", + }, + { label: "Amount", content: "₳ 12,350" }, +]; + +type GovernanceActionDetailsCardDataProps = { + type: string; + govActionId: string; + createdDate: string; + expiryDate: string; + isDataMissing: boolean; + isOneColumn: boolean; + isDashboard?: boolean; +}; + +export const GovernanceActionDetailsCardData = ({ + type, + govActionId, + createdDate, + expiryDate, + isDataMissing, + isOneColumn, + isDashboard, +}: GovernanceActionDetailsCardDataProps) => { + const { t } = useTranslation(); + const { screenWidth } = useScreenDimension(); + + const isModifiedPadding = + (isDashboard && screenWidth < 1168) ?? screenWidth < 900; + + return ( + + + {isDataMissing && } + + + {isDataMissing && ( + + )} + + + + + + + {/* TODO: To add option display of on-chain data when BE is ready */} + + + + ); +}; diff --git a/govtool/frontend/src/components/organisms/GovernanceActionsToVote.tsx b/govtool/frontend/src/components/organisms/GovernanceActionsToVote.tsx index 41eaa2bb2..b9ce93be9 100644 --- a/govtool/frontend/src/components/organisms/GovernanceActionsToVote.tsx +++ b/govtool/frontend/src/components/organisms/GovernanceActionsToVote.tsx @@ -1,14 +1,13 @@ -/* eslint-disable no-unsafe-optional-chaining */ import { useNavigate, generatePath } from "react-router-dom"; import { Box } from "@mui/material"; -import { Typography } from '@atoms'; -import { PATHS } from '@consts'; -import { useCardano } from '@context'; -import { useScreenDimension, useTranslation } from '@hooks'; -import { GovernanceActionCard } from '@molecules'; -import { getProposalTypeLabel, getFullGovActionId, openInNewTab } from '@utils'; -import { Slider } from './Slider'; +import { Typography } from "@atoms"; +import { PATHS } from "@consts"; +import { useCardano } from "@context"; +import { useScreenDimension, useTranslation } from "@hooks"; +import { GovernanceActionCard } from "@molecules"; +import { getProposalTypeLabel, getFullGovActionId, openInNewTab } from "@utils"; +import { Slider } from "@organisms"; type GovernanceActionsToVoteProps = { filters: string[]; @@ -34,7 +33,7 @@ export const GovernanceActionsToVote = ({ <> {!proposals.length ? ( - {t('govActions.noResultsForTheSearch')} + {t("govActions.noResultsForTheSearch")} ) : ( <> @@ -46,8 +45,8 @@ export const GovernanceActionsToVote = ({ className="keen-slider__slide" key={action.id} style={{ - overflow: 'visible', - width: 'auto', + overflow: "visible", + width: "auto", }} > - onDashboard && + // TODO: Add data validation + isDataMissing={false} + onClick={() => { + if ( + onDashboard && pendingTransaction.vote?.resourceId === - action?.txHash + action?.index - ? openInNewTab( + `${action.txHash ?? ""}${action.index ?? ""}` + ) { + openInNewTab( "https://adanordic.com/latest_transactions", - ) - : navigate( + ); + } else { + navigate( onDashboard ? generatePath( - PATHS.dashboardGovernanceActionsAction, - { - proposalId: getFullGovActionId( + PATHS.dashboardGovernanceActionsAction, + { + proposalId: getFullGovActionId( + action.txHash, + action.index, + ), + }, + ) + : PATHS.governanceActionsAction.replace( + ":proposalId", + getFullGovActionId( action.txHash, action.index, ), - }, - ) - : PATHS.governanceActionsAction.replace( - ":proposalId", - getFullGovActionId( - action.txHash, - action.index, ), - ), { state: { ...action }, }, - ) - } + ); + } + }} />
))} diff --git a/govtool/frontend/src/components/organisms/RegisterAsDRepSteps/DRepStorageInformation.tsx b/govtool/frontend/src/components/organisms/RegisterAsDRepSteps/DRepStorageInformation.tsx index 238e0f0a8..7fbed215e 100644 --- a/govtool/frontend/src/components/organisms/RegisterAsDRepSteps/DRepStorageInformation.tsx +++ b/govtool/frontend/src/components/organisms/RegisterAsDRepSteps/DRepStorageInformation.tsx @@ -1,4 +1,4 @@ -import { Dispatch, SetStateAction, useCallback } from "react"; +import { Dispatch, SetStateAction, useEffect } from "react"; import { Box } from "@mui/material"; import OpenInNewIcon from "@mui/icons-material/OpenInNew"; @@ -24,24 +24,28 @@ export const DRepStorageInformation = ({ const { control, errors, + generateMetadata, + getValues, isRegistrationAsDRepLoading, + onClickDownloadJson, registerAsDrep, watch, } = useRegisterAsdRepForm(); const { screenWidth } = useScreenDimension(); - // TODO: change on correct file name - const fileName = "fileName"; + const fileName = getValues("dRepName"); // TODO: Change link to correct - const openGuideAboutStoringInformation = useCallback( - () => openInNewTab("https://sancho.network/"), - [], - ); + const openGuideAboutStoringInformation = () => + openInNewTab("https://sancho.network/"); + + const isActionButtonDisabled = !watch("storingURL") || !!errors.storingURL; - const isActionButtonDisabled = !watch("storingURL"); + const onClickBack = () => setStep(3); - const onClickBack = useCallback(() => setStep(3), []); + useEffect(() => { + generateMetadata(); + }, []); return ( } sx={{ diff --git a/govtool/frontend/src/components/organisms/RegisterAsDRepSteps/DRepStoreDataInfo.tsx b/govtool/frontend/src/components/organisms/RegisterAsDRepSteps/DRepStoreDataInfo.tsx index 1e6839512..a8a22e110 100644 --- a/govtool/frontend/src/components/organisms/RegisterAsDRepSteps/DRepStoreDataInfo.tsx +++ b/govtool/frontend/src/components/organisms/RegisterAsDRepSteps/DRepStoreDataInfo.tsx @@ -18,13 +18,10 @@ export const DRepStoreDataInfo = ({ }) => { const { t } = useTranslation(); const { isMobile } = useScreenDimension(); - const { control, errors, isRegistrationAsDRepLoading, resetField, watch } = + const { control, errors, isRegistrationAsDRepLoading, watch } = useRegisterAsdRepForm(); - const onClickBackButton = () => { - setStep(2); - resetField("storeData"); - }; + const onClickBackButton = () => setStep(2); const isContinueDisabled = !watch("storeData"); diff --git a/govtool/frontend/src/components/organisms/RegisterAsDRepSteps/RegisterAsDRepForm.tsx b/govtool/frontend/src/components/organisms/RegisterAsDRepSteps/RegisterAsDRepForm.tsx index d2295b79f..88d11a3f3 100644 --- a/govtool/frontend/src/components/organisms/RegisterAsDRepSteps/RegisterAsDRepForm.tsx +++ b/govtool/frontend/src/components/organisms/RegisterAsDRepSteps/RegisterAsDRepForm.tsx @@ -4,17 +4,16 @@ import { Box } from "@mui/material"; import DeleteOutlineIcon from "@mui/icons-material/DeleteOutline"; import { Button, InfoText, Spacer, Typography } from "@atoms"; +import { Placeholders, Rules } from "@consts"; import { useRegisterAsdRepForm, useScreenDimension, useTranslation, } from "@hooks"; -import { URL_REGEX } from "@utils"; import { BgCard, ControlledField } from ".."; -import { Placeholders } from "@/consts"; -const MAX_NUMBER_OF_LINKS = 8; +const MAX_NUMBER_OF_LINKS = 7; export const RegisterAsDRepForm = ({ setStep, @@ -23,7 +22,7 @@ export const RegisterAsDRepForm = ({ }) => { const { t } = useTranslation(); const { isMobile } = useScreenDimension(); - const { control, errors, register, watch } = useRegisterAsdRepForm(); + const { control, errors, isError, register, watch } = useRegisterAsdRepForm(); const { append, fields: links, @@ -41,7 +40,7 @@ export const RegisterAsDRepForm = ({ const removeLink = useCallback((index: number) => remove(index), [remove]); - const isContinueButtonDisabled = !watch("dRepName"); + const isContinueButtonDisabled = !watch("dRepName") || isError; const renderLinks = useCallback( () => @@ -65,15 +64,10 @@ export const RegisterAsDRepForm = ({ layoutStyles={{ mb: 3 }} placeholder={Placeholders.LINK} name={`links.${index}.link`} - rules={{ - pattern: { - value: URL_REGEX, - message: t("createGovernanceAction.fields.validations.url"), - }, - }} + rules={Rules.LINK} /> )), - [links], + [errors, links], ); return ( @@ -98,6 +92,7 @@ export const RegisterAsDRepForm = ({ helpfulText={t("forms.registerAsDRep.dRepNameHelpfulText")} label={t("forms.registerAsDRep.dRepName")} name="dRepName" + rules={Rules.DREP_NAME} placeholder={t("forms.registerAsDRep.dRepNamePlaceholder")} /> @@ -115,6 +110,7 @@ export const RegisterAsDRepForm = ({ label={t("forms.registerAsDRep.email")} name="email" placeholder={t("forms.registerAsDRep.emailPlaceholder")} + rules={Rules.EMAIL} />

{t("registration.linksDescription")} - {t("registration.maximumLinks")} + {t("registration.maximumLinks", { + numberOfLinks: MAX_NUMBER_OF_LINKS, + })}

diff --git a/govtool/frontend/src/components/organisms/RegisterAsDRepSteps/WhatRetirementMeans.tsx b/govtool/frontend/src/components/organisms/RegisterAsDRepSteps/WhatRetirementMeans.tsx new file mode 100644 index 000000000..23f0fe766 --- /dev/null +++ b/govtool/frontend/src/components/organisms/RegisterAsDRepSteps/WhatRetirementMeans.tsx @@ -0,0 +1,112 @@ +import { useCallback, useState } from "react"; + +import { Typography } from "@atoms"; +import { useCardano, useModal } from "@context"; +import { useGetVoterInfo, useScreenDimension, useTranslation } from "@hooks"; + +import { BgCard } from ".."; + +export const WhatRetirementMeans = ({ + onClickCancel, +}: { + onClickCancel: () => void; +}) => { + const { + isPendingTransaction, + buildDRepRetirementCert, + buildSignSubmitConwayCertTx, + } = useCardano(); + const { t } = useTranslation(); + const { isMobile } = useScreenDimension(); + const { closeModal, openModal } = useModal(); + const [isRetirementLoading, setIsRetirementLoading] = + useState(false); + const { voter } = useGetVoterInfo(); + + const onSubmit = () => { + onClickCancel(); + closeModal(); + }; + + const retireAsDrep = useCallback(async () => { + try { + setIsRetirementLoading(true); + const isPendingTx = isPendingTransaction(); + if (isPendingTx) return; + if (!voter?.deposit) throw new Error(t("errors.appCannotGetDeposit")); + + const certBuilder = await buildDRepRetirementCert( + voter?.deposit.toString(), + ); + const result = await buildSignSubmitConwayCertTx({ + certBuilder, + type: "retireAsDrep", + voterDeposit: voter?.deposit.toString(), + }); + if (result) { + openModal({ + type: "statusModal", + state: { + buttonText: t("modals.common.goToDashboard"), + dataTestId: "retirement-transaction-submitted-modal", + link: "https://adanordic.com/latest_transactions", + message: t("modals.retirement.message"), + onSubmit, + status: "success", + title: t("modals.retirement.title"), + }, + }); + } + // eslint-disable-next-line @typescript-eslint/no-explicit-any + } catch (error: any) { + const errorMessage = error.info ? error.info : error; + + openModal({ + type: "statusModal", + state: { + buttonText: t("modals.common.goToDashboard"), + dataTestId: "retirement-transaction-error-modal", + message: errorMessage, + onSubmit, + status: "warning", + title: t("modals.common.oops"), + }, + }); + } finally { + setIsRetirementLoading(false); + } + }, [ + buildDRepRetirementCert, + buildSignSubmitConwayCertTx, + isPendingTransaction, + openModal, + voter?.deposit, + ]); + + return ( + + + {t("retirement.whatRetirementMeansTitle")} + + + {t("retirement.whatRetirementMeansDescription")} + + + ); +}; diff --git a/govtool/frontend/src/components/organisms/RegisterAsDRepSteps/index.ts b/govtool/frontend/src/components/organisms/RegisterAsDRepSteps/index.ts index 00566b6d4..29b5cb726 100644 --- a/govtool/frontend/src/components/organisms/RegisterAsDRepSteps/index.ts +++ b/govtool/frontend/src/components/organisms/RegisterAsDRepSteps/index.ts @@ -2,3 +2,4 @@ export * from "./DRepStorageInformation"; export * from "./DRepStoreDataInfo"; export * from "./RegisterAsDRepForm"; export * from "./RolesAndResponsibilities"; +export * from "./WhatRetirementMeans"; diff --git a/govtool/frontend/src/components/organisms/RetireAsSoleVoterBox.tsx b/govtool/frontend/src/components/organisms/RetireAsSoleVoterBox.tsx index f691d3d72..081e05d40 100644 --- a/govtool/frontend/src/components/organisms/RetireAsSoleVoterBox.tsx +++ b/govtool/frontend/src/components/organisms/RetireAsSoleVoterBox.tsx @@ -27,10 +27,10 @@ export const RetireAsSoleVoterBox = () => { const isPendingTx = isPendingTransaction(); if (isPendingTx) return; if (!voter?.deposit) { - throw new Error("Can not fetch deposit"); + throw new Error(t("errors.appCannotGetDeposit")); } const certBuilder = await buildDRepRetirementCert( - voter?.deposit?.toString() + voter?.deposit?.toString(), ); const result = await buildSignSubmitConwayCertTx({ certBuilder, diff --git a/govtool/frontend/src/components/organisms/Slider.tsx b/govtool/frontend/src/components/organisms/Slider.tsx index 577ca56a6..6be504364 100644 --- a/govtool/frontend/src/components/organisms/Slider.tsx +++ b/govtool/frontend/src/components/organisms/Slider.tsx @@ -1,15 +1,15 @@ -import { useCallback, useEffect, useMemo } from "react"; -import { Box, Link, Typography } from "@mui/material"; +import { useEffect, useMemo, useState } from "react"; +import { generatePath, useNavigate } from "react-router-dom"; +import { Box } from "@mui/material"; import { KeenSliderOptions } from "keen-slider"; import "keen-slider/keen-slider.min.css"; -import { ICONS, PATHS } from "@consts"; import { useCardano } from "@context"; -import { useScreenDimension, useSlider, useTranslation } from "@hooks"; -import { generatePath, useNavigate } from "react-router-dom"; -import styles from "./slider.module.css"; - -const SLIDER_MAX_LENGTH = 1000; +import { useScreenDimension, useTranslation, useSlider } from "@hooks"; +import { Button, Typography } from "@atoms"; +import { SliderArrows } from "@molecules"; +import { PATHS } from "@consts"; +import { theme } from "@/theme"; type SliderProps = { title: string; @@ -36,99 +36,121 @@ export const Slider = ({ searchPhrase, sorting, }: SliderProps) => { - const { isMobile, screenWidth, pagePadding } = useScreenDimension(); + const [isSliderInitialized, setIsSliderInitialized] = useState(false); + + const { isMobile, screenWidth } = useScreenDimension(); const navigate = useNavigate(); const { pendingTransaction } = useCardano(); const { t } = useTranslation(); + const { + palette: { primaryBlue, arcticWhite, lightBlue }, + } = theme; + const DEFAULT_SLIDER_CONFIG = { mode: "free", initial: 0, slides: { perView: "auto", - spacing: 24, + spacing: 20, }, } as KeenSliderOptions; - const { - currentRange, - sliderRef, - setPercentageValue, - instanceRef, - setCurrentRange, - } = useSlider({ + const isShowArrows = useMemo( + () => + // Arrows are to be show only on desktop view. + // 268 - side menu width; 40 - distance needed from the left on + // disconnected wallet (no side menu); 350 - gov action card width; + // other values are for paddings and margins + screenWidth < + (onDashboard ? 268 : 40) + 28 + dataLength * 350 + 20 * dataLength - 5, + [screenWidth, dataLength], + ); + + const { sliderRef, instanceRef, currentSlide, itemsPerView } = useSlider({ config: DEFAULT_SLIDER_CONFIG, - sliderMaxLength: SLIDER_MAX_LENGTH, }); - const paddingOffset = useMemo(() => { - const padding = onDashboard ? (isMobile ? 2 : 3.5) : pagePadding; - return padding * 8 * 2; - }, [isMobile, pagePadding]); - const refresh = () => { instanceRef.current?.update(instanceRef.current?.options); - setCurrentRange(0); instanceRef.current?.track.to(0); instanceRef.current?.moveToIdx(0); }; useEffect(() => { - refresh(); - }, [filters, sorting, searchPhrase, pendingTransaction.vote?.resourceId, data]); - - const rangeSliderCalculationElement = - dataLength < notSlicedDataLength - ? (screenWidth + - (onDashboard ? -290 - paddingOffset : -paddingOffset + 250)) / - 437 - : (screenWidth + (onDashboard ? -280 - paddingOffset : -paddingOffset)) / - 402; - - const handleLinkPress = useCallback(() => { - if (onDashboard) { - navigate( - generatePath(PATHS.dashboardGovernanceActionsCategory, { - category: navigateKey, - }), - ); - } else { - navigate( - generatePath(PATHS.governanceActionsCategory, { - category: navigateKey, - }), - ); + if (instanceRef.current) { + setIsSliderInitialized(true); } - }, [onDashboard]); + }, [instanceRef.current]); + + useEffect(() => { + refresh(); + }, [ + filters, + sorting, + searchPhrase, + pendingTransaction.vote?.resourceId, + data, + ]); return ( - - - {title} - - {isMobile && isShowAll && ( - - + + {title} + {(notSlicedDataLength > 6 || (isMobile && isShowAll)) && ( + + )} + + {isSliderInitialized && isShowArrows && dataLength > 1 && !isMobile && ( + )}
{data} - {!isMobile && isShowAll && dataLength < notSlicedDataLength && ( -
- - - {t("slider.viewAll")} - - arrow - -
- )}
- {!isMobile && Math.floor(rangeSliderCalculationElement) < dataLength && ( - - - - )}
); }; diff --git a/govtool/frontend/src/components/organisms/index.ts b/govtool/frontend/src/components/organisms/index.ts index bbded8e90..cccbc8400 100644 --- a/govtool/frontend/src/components/organisms/index.ts +++ b/govtool/frontend/src/components/organisms/index.ts @@ -17,6 +17,7 @@ export * from "./DrawerMobile"; export * from "./ExternalLinkModal"; export * from "./Footer"; export * from "./GovernanceActionDetailsCard"; +export * from "./GovernanceActionDetailsCardData"; export * from "./GovernanceActionsToVote"; export * from "./Hero"; export * from "./HomeCards"; diff --git a/govtool/frontend/src/consts/dRepActions/fields.ts b/govtool/frontend/src/consts/dRepActions/fields.ts new file mode 100644 index 000000000..025e7c72c --- /dev/null +++ b/govtool/frontend/src/consts/dRepActions/fields.ts @@ -0,0 +1,41 @@ +import i18n from "@/i18n"; +import { EMAIL_REGEX, NICKNAME_REGEX, URL_REGEX } from "@/utils"; + +export const Rules = { + BIO: { + maxLength: { + value: 500, + message: i18n.t("registration.fields.validations.maxLength", { + maxLength: 500, + }), + }, + }, + DREP_NAME: { + required: { + value: true, + message: i18n.t("registration.fields.validations.required"), + }, + pattern: { + value: NICKNAME_REGEX, + message: i18n.t("registration.fields.validations.nickname"), + }, + maxLength: { + value: 80, + message: i18n.t("registration.fields.validations.maxLength", { + maxLength: 80, + }), + }, + }, + EMAIL: { + pattern: { + value: EMAIL_REGEX, + message: i18n.t("registration.fields.validations.email"), + }, + }, + LINK: { + pattern: { + value: URL_REGEX, + message: i18n.t("registration.fields.validations.url"), + }, + }, +}; diff --git a/govtool/frontend/src/consts/dRepActions/index.ts b/govtool/frontend/src/consts/dRepActions/index.ts new file mode 100644 index 000000000..68294a70f --- /dev/null +++ b/govtool/frontend/src/consts/dRepActions/index.ts @@ -0,0 +1,2 @@ +export * from "./fields"; +export * from "./jsonContext"; diff --git a/govtool/frontend/src/consts/dRepActions/jsonContext.ts b/govtool/frontend/src/consts/dRepActions/jsonContext.ts new file mode 100644 index 000000000..78a6040df --- /dev/null +++ b/govtool/frontend/src/consts/dRepActions/jsonContext.ts @@ -0,0 +1,50 @@ +export const CIP_QQQ = + "https://github.com/cardano-foundation/CIPs/blob/master/CIP-QQQ/README.md#"; + +export const DREP_CONTEXT = { + "@language": "en-us", + CIP100: + "https://github.com/cardano-foundation/CIPs/blob/master/CIP-0100/README.md#", + CIPQQQ: CIP_QQQ, + hashAlgorithm: "CIP100:hashAlgorithm", + body: { + "@id": "CIPQQQ:body", + "@context": { + references: { + "@id": "CIPQQQ:references", + "@container": "@set" as const, + "@context": { + GovernanceMetadata: "CIP100:GovernanceMetadataReference", + Other: "CIP100:OtherReference", + label: "CIP100:reference-label", + uri: "CIP100:reference-uri", + referenceHash: { + "@id": "CIPQQQ:referenceHash", + "@context": { + hashDigest: "CIPQQQ:hashDigest", + hashAlgorithm: "CIP100:hashAlgorithm", + }, + }, + }, + }, + dRepName: "CIPQQQ:dRepName", + bio: "CIPQQQ:bio", + email: "CIPQQQ:email", + }, + }, + authors: { + "@id": "CIP100:authors", + "@container": "@set" as const, + "@context": { + name: "http://xmlns.com/foaf/0.1/name", + witness: { + "@id": "CIP100:witness", + "@context": { + witnessAlgorithm: "CIP100:witnessAlgorithm", + publicKey: "CIP100:publicKey", + signature: "CIP100:signature", + }, + }, + }, + }, +}; diff --git a/govtool/frontend/src/consts/externalDataModalConfig.ts b/govtool/frontend/src/consts/externalDataModalConfig.ts new file mode 100644 index 000000000..1508004f4 --- /dev/null +++ b/govtool/frontend/src/consts/externalDataModalConfig.ts @@ -0,0 +1,41 @@ +import { ModalState } from "@/context"; +import I18n from "@/i18n"; + +export enum MetadataHashValidationErrors { + INVALID_URL = "Invalid URL", + INVALID_JSON = "Invalid JSON", + INVALID_HASH = "Invalid hash", + FETCH_ERROR = "Error fetching data", +} + +const externalDataDoesntMatchModal = { + status: "warning", + title: I18n.t("modals.externalDataDoesntMatch.title"), + message: I18n.t("modals.externalDataDoesntMatch.message"), + buttonText: I18n.t("modals.externalDataDoesntMatch.buttonText"), + cancelText: I18n.t("modals.externalDataDoesntMatch.cancelRegistrationText"), + feedbackText: I18n.t("modals.externalDataDoesntMatch.feedbackText"), +} as const; + +const urlCannotBeFound = { + status: "warning", + title: I18n.t("modals.urlCannotBeFound.title"), + message: I18n.t("modals.urlCannotBeFound.message"), + link: "https://docs.sanchogov.tools", + linkText: I18n.t("modals.urlCannotBeFound.linkText"), + buttonText: I18n.t("modals.urlCannotBeFound.buttonText"), + cancelText: I18n.t("modals.urlCannotBeFound.cancelRegistrationText"), + feedbackText: I18n.t("modals.urlCannotBeFound.feedbackText"), +}; + +export const storageInformationErrorModals: Record< + MetadataHashValidationErrors, + ModalState< + typeof externalDataDoesntMatchModal | typeof urlCannotBeFound + >["state"] +> = { + [MetadataHashValidationErrors.INVALID_URL]: urlCannotBeFound, + [MetadataHashValidationErrors.FETCH_ERROR]: urlCannotBeFound, + [MetadataHashValidationErrors.INVALID_JSON]: externalDataDoesntMatchModal, + [MetadataHashValidationErrors.INVALID_HASH]: externalDataDoesntMatchModal, +}; diff --git a/govtool/frontend/src/consts/governanceAction/index.ts b/govtool/frontend/src/consts/governanceAction/index.ts index 288b6cd15..f25d9d5b2 100644 --- a/govtool/frontend/src/consts/governanceAction/index.ts +++ b/govtool/frontend/src/consts/governanceAction/index.ts @@ -1,5 +1,3 @@ export * from "./fields"; export * from "./filters"; export * from "./sorting"; -export * from "./modalConfig"; -export * from "./metadataHashValidationErrors"; diff --git a/govtool/frontend/src/consts/governanceAction/metadataHashValidationErrors.ts b/govtool/frontend/src/consts/governanceAction/metadataHashValidationErrors.ts deleted file mode 100644 index 0d3479ba4..000000000 --- a/govtool/frontend/src/consts/governanceAction/metadataHashValidationErrors.ts +++ /dev/null @@ -1,6 +0,0 @@ -export enum MetadataHashValidationErrors { - INVALID_URL = "Invalid URL", - INVALID_JSON = "Invalid JSON", - INVALID_HASH = "Invalid hash", - FETCH_ERROR = "Error fetching data", -} diff --git a/govtool/frontend/src/consts/governanceAction/modalConfig.ts b/govtool/frontend/src/consts/governanceAction/modalConfig.ts deleted file mode 100644 index e38aae9c4..000000000 --- a/govtool/frontend/src/consts/governanceAction/modalConfig.ts +++ /dev/null @@ -1,50 +0,0 @@ -import { ModalState } from "@/context"; -import I18n from "@/i18n"; - -import { MetadataHashValidationErrors } from "./metadataHashValidationErrors"; - -const externalDataDoesntMatchModal = { - status: "warning", - title: I18n.t("createGovernanceAction.modals.externalDataDoesntMatch.title"), - message: I18n.t( - "createGovernanceAction.modals.externalDataDoesntMatch.message", - ), - buttonText: I18n.t( - "createGovernanceAction.modals.externalDataDoesntMatch.buttonText", - ), - cancelText: I18n.t( - "createGovernanceAction.modals.externalDataDoesntMatch.cancelRegistrationText", - ), - feedbackText: I18n.t( - "createGovernanceAction.modals.externalDataDoesntMatch.feedbackText", - ), -} as const; - -const urlCannotBeFound = { - status: "warning", - title: I18n.t("createGovernanceAction.modals.urlCannotBeFound.title"), - message: I18n.t("createGovernanceAction.modals.urlCannotBeFound.message"), - link: "https://docs.sanchogov.tools", - linkText: I18n.t("createGovernanceAction.modals.urlCannotBeFound.linkText"), - buttonText: I18n.t( - "createGovernanceAction.modals.urlCannotBeFound.buttonText", - ), - cancelText: I18n.t( - "createGovernanceAction.modals.urlCannotBeFound.cancelRegistrationText", - ), - feedbackText: I18n.t( - "createGovernanceAction.modals.urlCannotBeFound.feedbackText", - ), -}; - -export const storageInformationErrorModals: Record< - MetadataHashValidationErrors, - ModalState< - typeof externalDataDoesntMatchModal | typeof urlCannotBeFound - >["state"] -> = { - [MetadataHashValidationErrors.INVALID_URL]: urlCannotBeFound, - [MetadataHashValidationErrors.FETCH_ERROR]: urlCannotBeFound, - [MetadataHashValidationErrors.INVALID_JSON]: externalDataDoesntMatchModal, - [MetadataHashValidationErrors.INVALID_HASH]: externalDataDoesntMatchModal, -}; diff --git a/govtool/frontend/src/consts/icons.ts b/govtool/frontend/src/consts/icons.ts index 2a5fc394d..dfabf260d 100644 --- a/govtool/frontend/src/consts/icons.ts +++ b/govtool/frontend/src/consts/icons.ts @@ -8,6 +8,7 @@ export const ICONS = { closeIcon: "/icons/Close.svg", closeWhiteIcon: "/icons/CloseWhite.svg", copyBlueIcon: "/icons/CopyBlue.svg", + copyBlueThinIcon: "/icons/CopyBlueThin.svg", copyIcon: "/icons/Copy.svg", copyWhiteIcon: "/icons/CopyWhite.svg", dashboardActiveIcon: "/icons/DashboardActive.svg", @@ -25,6 +26,7 @@ export const ICONS = { guidesIcon: "/icons/Guides.svg", helpIcon: "/icons/Help.svg", link: "/icons/Link.svg", + share: "/icons/Share.svg", sortActiveIcon: "/icons/SortActive.svg", sortIcon: "/icons/Sort.svg", sortWhiteIcon: "/icons/SortWhite.svg", diff --git a/govtool/frontend/src/consts/index.ts b/govtool/frontend/src/consts/index.ts index 201aacbb1..22a9c3bbc 100644 --- a/govtool/frontend/src/consts/index.ts +++ b/govtool/frontend/src/consts/index.ts @@ -1,4 +1,6 @@ +export * from "./externalDataModalConfig"; export * from "./colors"; +export * from "./dRepActions"; export * from "./governanceAction"; export * from "./icons"; export * from "./images"; diff --git a/govtool/frontend/src/consts/paths.ts b/govtool/frontend/src/consts/paths.ts index 679962a36..1e2eddda5 100644 --- a/govtool/frontend/src/consts/paths.ts +++ b/govtool/frontend/src/consts/paths.ts @@ -1,22 +1,23 @@ export const PATHS = { createGovernanceAction: "/create_governance_action", + dashboard: "/dashboard", + dashboardGovernanceActions: "/connected/governance_actions", dashboardGovernanceActionsAction: "/connected/governance_actions/:proposalId", dashboardGovernanceActionsCategory: "/connected/governance_actions/category/:category", - dashboardGovernanceActions: "/connected/governance_actions", - dashboard: "/dashboard", delegateTodRep: "/delegate", error: "/error", faqs: "/faqs", governanceActions: "/governance_actions", governanceActionsAction: "/governance_actions/:proposalId", + governanceActionsCategory: "/governance_actions/category/:category", governanceActionsCategoryAction: "/governance_actions/category/:category/:proposalId", - governanceActionsCategory: "/governance_actions/category/:category", guides: "/guides", home: "/", registerAsdRep: "/register", registerAsSoleVoter: "/register_sole_voter", + retireAsDrep: "/retire_drep", retireAsSoleVoter: "/retire_sole_voter", stakeKeys: "/stake_keys", updateMetadata: "/update_metadata", diff --git a/govtool/frontend/src/context/getUtxos.ts b/govtool/frontend/src/context/getUtxos.ts index 23fc0a198..6888846a8 100644 --- a/govtool/frontend/src/context/getUtxos.ts +++ b/govtool/frontend/src/context/getUtxos.ts @@ -77,7 +77,6 @@ export const getUtxos = async ( return utxos; } catch (err) { Sentry.captureException(err); - // eslint-disable-next-line no-console console.error(err); } }; diff --git a/govtool/frontend/src/context/pendingTransaction/types.ts b/govtool/frontend/src/context/pendingTransaction/types.ts index f6aae4ade..a44c5f6e0 100644 --- a/govtool/frontend/src/context/pendingTransaction/types.ts +++ b/govtool/frontend/src/context/pendingTransaction/types.ts @@ -15,14 +15,14 @@ export type TransactionType = export type TransactionStateWithoutResource = { type: TransactionTypeWithoutResource; transactionHash: string; - time: Date; + time: string; resourceId?: never; }; export type TransactionStateWithResource = { type: TransactionTypeWithResource; transactionHash: string; - time: Date; + time: string; resourceId: string; }; diff --git a/govtool/frontend/src/context/pendingTransaction/usePendingTransaction.ts b/govtool/frontend/src/context/pendingTransaction/usePendingTransaction.ts index 18f1e4a7c..bd537754b 100644 --- a/govtool/frontend/src/context/pendingTransaction/usePendingTransaction.ts +++ b/govtool/frontend/src/context/pendingTransaction/usePendingTransaction.ts @@ -20,7 +20,6 @@ const DB_SYNC_REFRESH_TIME = 3 * 1000; // 3 SECONDS const DB_SYNC_MAX_ATTEMPTS = 10; type UsePendingTransactionProps = { - dRepID: string; isEnabled: boolean; stakeKey: string | undefined; }; @@ -28,7 +27,6 @@ type UsePendingTransactionProps = { export const usePendingTransaction = ({ isEnabled, stakeKey, - dRepID, }: UsePendingTransactionProps) => { const { t } = useTranslation(); const { openModal, closeModal } = useModal(); @@ -57,11 +55,11 @@ export const usePendingTransaction = ({ const fromLocalStorage = getItemFromLocalStorage( `${PENDING_TRANSACTION_KEY}_${stakeKey}` ); - setTransaction( - fromLocalStorage - ? { ...fromLocalStorage, time: new Date(fromLocalStorage.time) } - : null - ); + if (!fromLocalStorage) setTransaction(null); + else setTransaction({ + ...fromLocalStorage, + resourceId: fromLocalStorage.resourceId ?? undefined, + }); } }, [isEnabled, stakeKey]); @@ -84,9 +82,7 @@ export const usePendingTransaction = ({ if (isEnabled) { const desiredResult = getDesiredResult( type, - dRepID, resourceId, - stakeKey ); const queryKey = getQueryKey(type, transaction); @@ -105,13 +101,13 @@ export const usePendingTransaction = ({ await wait(DB_SYNC_REFRESH_TIME); } } - - if (isTransactionExpired(transaction.time)) { - addErrorAlert(t(`alerts.${type}.failed`)); - resetTransaction(); - } } } + + if (isTransactionExpired(transaction.time)) { + addErrorAlert(t(`alerts.${type}.failed`)); + resetTransaction(); + } }; let interval = setInterval(checkTransaction, TRANSACTION_REFRESH_TIME); @@ -120,7 +116,7 @@ export const usePendingTransaction = ({ if (isEnabled && transaction) { addWarningAlert(t("alerts.transactionInProgress"), 10000); } - }, [transaction]); + }, [isEnabled, transaction]); const isPendingTransaction = useCallback(() => { if (transaction) { @@ -144,14 +140,17 @@ export const usePendingTransaction = ({ const updateTransaction = (data: Omit) => { const newTransaction = { - time: new Date(), + time: new Date().toISOString(), ...data, } as TransactionState; setTransaction(newTransaction); setItemToLocalStorage( `${PENDING_TRANSACTION_KEY}_${stakeKey}`, - JSON.stringify(newTransaction) + { + ...newTransaction, + resourceId: newTransaction.resourceId || null, + } ); }; @@ -162,5 +161,5 @@ export const usePendingTransaction = ({ }; }; -const isTransactionExpired = (time: Date): boolean => - Date.now() - time.getTime() > TIME_TO_EXPIRE_TRANSACTION; +const isTransactionExpired = (time: string): boolean => + Date.now() - new Date(time).getTime() > TIME_TO_EXPIRE_TRANSACTION; diff --git a/govtool/frontend/src/context/pendingTransaction/utils.tsx b/govtool/frontend/src/context/pendingTransaction/utils.tsx index 916a994ff..ed7195b3d 100644 --- a/govtool/frontend/src/context/pendingTransaction/utils.tsx +++ b/govtool/frontend/src/context/pendingTransaction/utils.tsx @@ -4,17 +4,14 @@ import { TransactionType, TransactionState } from "./types"; export const getDesiredResult = ( type: TransactionType, - dRepID: string, resourceId: string | undefined, - stakeKey?: string ) => { switch (type) { case "delegate": { // current delegation - if (resourceId === dRepID) return dRepID; if (resourceId === "no confidence") return "drep_always_no_confidence"; if (resourceId === "abstain") return "drep_always_abstain"; - return stakeKey; + return resourceId; } case "registerAsDrep": case "registerAsSoleVoter": @@ -38,9 +35,9 @@ export const getQueryKey = ( case "retireAsDrep": case "registerAsSoleVoter": case "retireAsSoleVoter": - return [QUERY_KEYS.useGetDRepInfoKey, transaction]; + return [QUERY_KEYS.useGetDRepInfoKey, transaction?.transactionHash]; case "delegate": - return [QUERY_KEYS.getAdaHolderCurrentDelegationKey, transaction]; + return [QUERY_KEYS.getAdaHolderCurrentDelegationKey, transaction?.transactionHash]; default: return undefined; } @@ -58,7 +55,7 @@ export const refetchData = async ( // eslint-disable-next-line @typescript-eslint/no-explicit-any const data = await queryClient.getQueryData(queryKey); - if (type === "delegate") return data.currentDelegation; + if (type === "delegate") return data; if (type === "registerAsDrep" || type === "retireAsDrep") return data.isRegisteredAsDRep; if (type === "registerAsSoleVoter" || type === "retireAsSoleVoter") return data.isRegisteredAsSoleVoter; return undefined; diff --git a/govtool/frontend/src/context/wallet.tsx b/govtool/frontend/src/context/wallet.tsx index 75eb48eb0..c60b6cbaf 100644 --- a/govtool/frontend/src/context/wallet.tsx +++ b/govtool/frontend/src/context/wallet.tsx @@ -1,13 +1,10 @@ -// TODO: enable eslint and fix all the errors with wallet refactor -/* eslint-disable */ -// @ts-nocheck import { createContext, useCallback, useContext, useMemo, useState, -} from 'react'; +} from "react"; import { Address, BigNum, @@ -43,16 +40,16 @@ import { GovernanceAction, TreasuryWithdrawals, TreasuryWithdrawalsAction, -} from '@emurgo/cardano-serialization-lib-asmjs'; -import { Buffer } from 'buffer'; -import { useNavigate } from 'react-router-dom'; -import { Link } from '@mui/material'; -import * as Sentry from '@sentry/react'; -import { Trans } from 'react-i18next'; - -import { PATHS } from '@consts'; -import { CardanoApiWallet, Protocol } from '@models'; -import type { StatusModalState } from '@organisms'; +} from "@emurgo/cardano-serialization-lib-asmjs"; +import { Buffer } from "buffer"; +import { useNavigate } from "react-router-dom"; +import { Link } from "@mui/material"; +import * as Sentry from "@sentry/react"; +import { Trans } from "react-i18next"; + +import { PATHS } from "@consts"; +import { CardanoApiWallet, Protocol } from "@models"; +import type { StatusModalState } from "@organisms"; import { checkIsMaintenanceOn, generateAnchor, @@ -64,16 +61,17 @@ import { SANCHO_INFO_KEY, setItemToLocalStorage, WALLET_LS_KEY, -} from '@utils'; -import { getEpochParams } from '@services'; -import { useTranslation } from '@hooks'; -import { getUtxos } from './getUtxos'; -import { useModal, useSnackbar } from '.'; +} from "@utils"; +import { getEpochParams } from "@services"; +import { useTranslation } from "@hooks"; +import { getUtxos } from "./getUtxos"; +import { useModal, useSnackbar } from "."; import { PendingTransaction, - TransactionType, + TransactionStateWithResource, + TransactionStateWithoutResource, usePendingTransaction, -} from './pendingTransaction'; +} from "./pendingTransaction"; interface Props { children: React.ReactNode; @@ -97,7 +95,17 @@ type TreasuryProps = { url: string; }; -interface CardanoContext { +type BuildSignSubmitConwayCertTxArgs = { + certBuilder?: CertificatesBuilder; + govActionBuilder?: VotingProposalBuilder; + votingBuilder?: VotingBuilder; + voterDeposit?: string; +} & ( + | Pick + | Pick + ); + +interface CardanoContextType { address?: string; disconnectWallet: () => Promise; enable: (walletName: string) => Promise; @@ -119,24 +127,15 @@ interface CardanoContext { type, votingBuilder, voterDeposit, - }: { - certBuilder?: CertificatesBuilder; - govActionBuilder?: VotingProposalBuilder; - resourceId?: string; - type: TransactionType; - votingBuilder?: VotingBuilder; - voterDeposit?: string; - }) => Promise; + }: BuildSignSubmitConwayCertTxArgs) => Promise; buildDRepRegCert: ( url?: string, hash?: string, - hash?: string, ) => Promise; buildVoteDelegationCert: (vote: string) => Promise; buildDRepUpdateCert: ( url?: string, hash?: string, - hash?: string, ) => Promise; buildDRepRetirementCert: ( voterDeposit: string, @@ -147,7 +146,6 @@ interface CardanoContext { index: number, cip95MetadataURL?: string, cip95MetadataHash?: string, - cip95MetadataHash?: string, ) => Promise; pendingTransaction: PendingTransaction; isPendingTransaction: () => boolean; @@ -160,7 +158,7 @@ interface CardanoContext { } type Utxos = { - txid: any; + txid: unknown; txindx: number; amount: string; str: string; @@ -168,9 +166,9 @@ type Utxos = { TransactionUnspentOutput: TransactionUnspentOutput; }[]; -const NETWORK = import.meta.env.VITE_NETWORK_FLAG; +const NETWORK = +import.meta.env.VITE_NETWORK_FLAG; -const CardanoContext = createContext({} as CardanoContext); +const CardanoContext = createContext({} as CardanoContextType); CardanoContext.displayName = 'CardanoContext'; const CardanoProvider = (props: Props) => { @@ -180,13 +178,12 @@ const CardanoProvider = (props: Props) => { undefined, ); const [address, setAddress] = useState(undefined); - const [pubDRepKey, setPubDRepKey] = useState(''); - const [dRepID, setDRepID] = useState(''); - const [dRepIDBech32, setDRepIDBech32] = useState(''); + const [pubDRepKey, setPubDRepKey] = useState(""); + const [dRepID, setDRepID] = useState(""); + const [dRepIDBech32, setDRepIDBech32] = useState(""); const [stakeKey, setStakeKey] = useState(undefined); const [stakeKeys, setStakeKeys] = useState([]); const [isMainnet, setIsMainnet] = useState(false); - const { openModal, closeModal } = useModal(); const [registeredStakeKeysListState, setRegisteredPubStakeKeysState] = useState([]); const [error, setError] = useState(undefined); @@ -201,13 +198,13 @@ const CardanoProvider = (props: Props) => { const epochParams = getItemFromLocalStorage(PROTOCOL_PARAMS_KEY); const { isPendingTransaction, updateTransaction, pendingTransaction } = - usePendingTransaction({ dRepID, isEnabled, stakeKey }); + usePendingTransaction({ isEnabled, stakeKey }); const getChangeAddress = async (enabledApi: CardanoApiWallet) => { try { const raw = await enabledApi.getChangeAddress(); const changeAddress = Address.from_bytes( - Buffer.from(raw, 'hex'), + Buffer.from(raw, "hex"), ).to_bech32(); setWalletState((prev) => ({ ...prev, changeAddress })); } catch (err) { @@ -221,7 +218,7 @@ const CardanoProvider = (props: Props) => { const raw = await enabledApi.getUsedAddresses(); const rawFirst = raw[0]; const usedAddress = Address.from_bytes( - Buffer.from(rawFirst, 'hex'), + Buffer.from(rawFirst, "hex"), ).to_bech32(); setWalletState((prev) => ({ ...prev, usedAddress })); } catch (err) { @@ -240,16 +237,16 @@ const CardanoProvider = (props: Props) => { try { // Check that this wallet supports CIP-95 connection if (!window.cardano[walletName].supportedExtensions) { - throw new Error(t('errors.walletNoCIP30Support')); + throw new Error(t("errors.walletNoCIP30Support")); } else if ( !window.cardano[walletName].supportedExtensions.some( (item) => item.cip === 95, ) ) { - throw new Error(t('errors.walletNoCIP30Nor90Support')); + throw new Error(t("errors.walletNoCIP30Nor90Support")); } // Enable wallet connection - const enabledApi = await window.cardano[walletName] + const enabledApi: CardanoApiWallet = await window.cardano[walletName] .enable({ extensions: [{ cip: 95 }], }) @@ -264,23 +261,23 @@ const CardanoProvider = (props: Props) => { // Check if wallet has enabled the CIP-95 extension const enabledExtensions = await enabledApi.getExtensions(); if (!enabledExtensions.some((item) => item.cip === 95)) { - throw new Error(t('errors.walletNoCIP90FunctionsEnabled')); + throw new Error(t("errors.walletNoCIP90FunctionsEnabled")); } const network = await enabledApi.getNetworkId(); - if (network != NETWORK) { + if (network !== NETWORK) { throw new Error( t('errors.tryingConnectTo', { - networkFrom: network == 1 ? 'mainnet' : 'testnet', - networkTo: network != 1 ? 'mainnet' : 'testnet', + networkFrom: network === 1 ? 'mainnet' : 'testnet', + networkTo: network !== 1 ? 'mainnet' : 'testnet', }), ); } - setIsMainnet(network == 1); + setIsMainnet(network === 1); // Check and set wallet address const usedAddresses = await enabledApi.getUsedAddresses(); const unusedAddresses = await enabledApi.getUnusedAddresses(); if (!usedAddresses.length && !unusedAddresses.length) { - throw new Error(t('errors.noAddressesFound')); + throw new Error(t("errors.noAddressesFound")); } if (!usedAddresses.length) { setAddress(unusedAddresses[0]); @@ -297,8 +294,8 @@ const CardanoProvider = (props: Props) => { let stakeKeysList; if (registeredStakeKeysList.length > 0) { - stakeKeysList = registeredStakeKeysList.map((stakeKey) => { - const stakeKeyHash = PublicKey.from_hex(stakeKey).hash(); + stakeKeysList = registeredStakeKeysList.map((key) => { + const stakeKeyHash = PublicKey.from_hex(key).hash(); const stakeCredential = Credential.from_keyhash(stakeKeyHash); if (network === 1) { return RewardAddress.new(1, stakeCredential) @@ -311,8 +308,8 @@ const CardanoProvider = (props: Props) => { }); } else { console.warn(t('warnings.usingUnregisteredStakeKeys')); - stakeKeysList = unregisteredStakeKeysList.map((stakeKey) => { - const stakeKeyHash = PublicKey.from_hex(stakeKey).hash(); + stakeKeysList = unregisteredStakeKeysList.map((key) => { + const stakeKeyHash = PublicKey.from_hex(key).hash(); const stakeCredential = Credential.from_keyhash(stakeKeyHash); if (network === 1) { return RewardAddress.new(1, stakeCredential) @@ -344,32 +341,34 @@ const CardanoProvider = (props: Props) => { stakeKeySet = true; } const dRepIDs = await getPubDRepID(enabledApi); - setPubDRepKey(dRepIDs?.dRepKey || ''); - setDRepID(dRepIDs?.dRepID || ''); - setDRepIDBech32(dRepIDs?.dRepIDBech32 || ''); + setPubDRepKey(dRepIDs?.dRepKey || ""); + setDRepID(dRepIDs?.dRepID || ""); + setDRepIDBech32(dRepIDs?.dRepIDBech32 || ""); setItemToLocalStorage(`${WALLET_LS_KEY}_name`, walletName); const protocol = await getEpochParams(); setItemToLocalStorage(PROTOCOL_PARAMS_KEY, protocol); - return { status: t('ok'), stakeKey: stakeKeySet }; + return { status: t("ok"), stakeKey: stakeKeySet }; } catch (e) { Sentry.captureException(e); console.error(e); setError(`${e}`); setAddress(undefined); setWalletApi(undefined); - setPubDRepKey(''); + setPubDRepKey(""); setStakeKey(undefined); setIsEnabled(false); + // eslint-disable-next-line no-throw-literal throw { status: 'ERROR', - error: `${e == undefined ? t('errors.somethingWentWrong') : e}`, + error: `${e ?? t('errors.somethingWentWrong')}`, }; } finally { setIsEnableLoading(null); } } + // eslint-disable-next-line no-throw-literal throw { status: 'ERROR', error: t('errors.somethingWentWrong') }; }, [isEnabled, stakeKeys], @@ -415,6 +414,7 @@ const CardanoProvider = (props: Props) => { const getTxUnspentOutputs = async (utxos: Utxos) => { const txOutputs = TransactionUnspentOutputs.new(); + // eslint-disable-next-line no-restricted-syntax for (const utxo of utxos) { txOutputs.add(utxo.TransactionUnspentOutput); } @@ -430,14 +430,7 @@ const CardanoProvider = (props: Props) => { type, votingBuilder, voterDeposit, - }: { - certBuilder?: CertificatesBuilder; - govActionBuilder?: VotingProposalBuilder; - resourceId?: string; - type: TransactionType; - votingBuilder?: VotingBuilder; - voterDeposit?: string; - }) => { + }: BuildSignSubmitConwayCertTxArgs) => { await checkIsMaintenanceOn(); const isPendingTx = isPendingTransaction(); if (isPendingTx) return; @@ -446,7 +439,7 @@ const CardanoProvider = (props: Props) => { const txBuilder = await initTransactionBuilder(); if (!txBuilder) { - throw new Error(t('errors.appCannotCreateTransaction')); + throw new Error(t("errors.appCannotCreateTransaction")); } if (certBuilder) { @@ -475,10 +468,10 @@ const CardanoProvider = (props: Props) => { ); // Add output of 1 ADA to the address of our wallet - let outputValue = BigNum.from_str('1000000'); + let outputValue = BigNum.from_str("1000000"); if ( - (type === 'retireAsDrep' || type === 'retireAsSoleVoter') && + (type === "retireAsDrep" || type === "retireAsSoleVoter") && voterDeposit ) { outputValue = outputValue.checked_add(BigNum.from_str(voterDeposit)); @@ -491,7 +484,7 @@ const CardanoProvider = (props: Props) => { const utxos = await getUtxos(walletApi); if (!utxos) { - throw new Error(t('errors.appCannotGetUtxos')); + throw new Error(t("errors.appCannotGetUtxos")); } // Find the available UTXOs in the wallet and use them as Inputs for the transaction const txUnspentOutputs = await getTxUnspentOutputs(utxos); @@ -518,11 +511,11 @@ const CardanoProvider = (props: Props) => { // Create witness set object using the witnesses provided by the wallet txVkeyWitnesses = TransactionWitnessSet.from_bytes( - Buffer.from(txVkeyWitnesses, 'hex'), + Buffer.from(txVkeyWitnesses, "hex"), ); const vkeys = txVkeyWitnesses.vkeys(); - if (!vkeys) throw new Error(t('errors.appCannotGetVkeys')); + if (!vkeys) throw new Error(t("errors.appCannotGetVkeys")); transactionWitnessSet.set_vkeys(vkeys); // Build transaction with witnesses @@ -539,9 +532,11 @@ const CardanoProvider = (props: Props) => { resourceId, }); + // eslint-disable-next-line no-console console.log(signedTx.to_hex(), 'signed tx cbor'); return resultHash; - // TODO: type error + // TODO: type error + // eslint-disable-next-line @typescript-eslint/no-shadow, @typescript-eslint/no-explicit-any } catch (error: any) { const walletName = getItemFromLocalStorage(`${WALLET_LS_KEY}_name`); const isWalletConnected = await window.cardano[walletName].isEnabled(); @@ -551,7 +546,7 @@ const CardanoProvider = (props: Props) => { } Sentry.captureException(error); - console.error(error, 'error'); + console.error(error, "error"); throw error?.info ?? error; } }, @@ -565,7 +560,7 @@ const CardanoProvider = (props: Props) => { const certBuilder = CertificatesBuilder.new(); let stakeCred; if (!stakeKey) { - throw new Error(t('errors.noStakeKeySelected')); + throw new Error(t("errors.noStakeKeySelected")); } // Remove network tag from stake key hash const stakeKeyHash = Ed25519KeyHash.from_hex(stakeKey.substring(2)); @@ -580,11 +575,11 @@ const CardanoProvider = (props: Props) => { // Create correct DRep let targetDRep; - if (target === 'abstain') { + if (target === "abstain") { targetDRep = DRep.new_always_abstain(); - } else if (target === 'no confidence') { + } else if (target === "no confidence") { targetDRep = DRep.new_always_no_confidence(); - } else if (target.includes('drep')) { + } else if (target.includes("drep")) { targetDRep = DRep.new_key_hash(Ed25519KeyHash.from_bech32(target)); } else { targetDRep = DRep.new_key_hash(Ed25519KeyHash.from_hex(target)); @@ -597,7 +592,7 @@ const CardanoProvider = (props: Props) => { return certBuilder; } catch (e) { Sentry.captureException(e); - console.log(e); + console.error(e); throw e; } }, @@ -629,7 +624,7 @@ const CardanoProvider = (props: Props) => { anchor, ); } else { - console.log(t('errors.notUsingAnchor')); + console.error(t('errors.notUsingAnchor')); dRepRegCert = DrepRegistration.new( dRepCred, BigNum.from_str(`${epochParams.drep_deposit}`), @@ -675,7 +670,7 @@ const CardanoProvider = (props: Props) => { return certBuilder; } catch (e) { Sentry.captureException(e); - console.log(e); + console.error(e); throw e; } }, @@ -703,7 +698,7 @@ const CardanoProvider = (props: Props) => { return certBuilder; } catch (e) { Sentry.captureException(e); - console.log(e); + console.error(e); throw e; } }, @@ -730,9 +725,9 @@ const CardanoProvider = (props: Props) => { ); let votingChoice; - if (voteChoice === 'yes') { + if (voteChoice === "yes") { votingChoice = 1; - } else if (voteChoice === 'no') { + } else if (voteChoice === "no") { votingChoice = 0; } else { votingChoice = 2; @@ -756,7 +751,7 @@ const CardanoProvider = (props: Props) => { return votingBuilder; } catch (e) { Sentry.captureException(e); - console.log(e); + console.error(e); throw e; } }, @@ -766,11 +761,11 @@ const CardanoProvider = (props: Props) => { const getRewardAddress = useCallback(async () => { const addresses = await walletApi?.getRewardAddresses(); if (!addresses) { - throw new Error('Can not get reward addresses from wallet.'); + throw new Error("Can not get reward addresses from wallet."); } const firstAddress = addresses[0]; const bech32Address = Address.from_bytes( - Buffer.from(firstAddress, 'hex'), + Buffer.from(firstAddress, "hex"), ).to_bech32(); return RewardAddress.from_address(Address.from_bech32(bech32Address)); @@ -788,7 +783,7 @@ const CardanoProvider = (props: Props) => { const anchor = generateAnchor(url, hash); const rewardAddr = await getRewardAddress(); - if (!rewardAddr) throw new Error('Can not get reward address'); + if (!rewardAddr) throw new Error("Can not get reward address"); // Create voting proposal const votingProposal = VotingProposal.new( @@ -816,7 +811,7 @@ const CardanoProvider = (props: Props) => { Address.from_bech32(receivingAddress), ); - if (!treasuryTarget) throw new Error('Can not get tresasury target'); + if (!treasuryTarget) throw new Error("Can not get tresasury target"); const myWithdrawal = BigNum.from_str(amount); const withdrawals = TreasuryWithdrawals.new(); @@ -830,7 +825,7 @@ const CardanoProvider = (props: Props) => { const rewardAddr = await getRewardAddress(); - if (!rewardAddr) throw new Error('Can not get reward address'); + if (!rewardAddr) throw new Error("Can not get reward address"); // Create voting proposal const votingProposal = VotingProposal.new( treasuryGovAct, @@ -914,7 +909,7 @@ function useCardano() { const { t } = useTranslation(); if (context === undefined) { - throw new Error(t('errors.useCardano')); + throw new Error(t("errors.useCardano")); } const enable = useCallback( @@ -927,22 +922,22 @@ function useCardano() { if (!result.error) { closeModal(); if (result.stakeKey) { - addSuccessAlert(t('alerts.walletConnected'), 3000); + addSuccessAlert(t("alerts.walletConnected"), 3000); } if (!isSanchoInfoShown) { openModal({ - type: 'statusModal', + type: "statusModal", state: { - status: 'info', - dataTestId: 'info-about-sancho-net-modal', + status: "info", + dataTestId: "info-about-sancho-net-modal", message: (

- {t('system.sanchoNetIsBeta')} + {t("system.sanchoNetIsBeta")} openInNewTab('https://sancho.network/')} - sx={{ cursor: 'pointer' }} + onClick={() => openInNewTab("https://sancho.network/")} + sx={{ cursor: "pointer" }} > - {t('system.sanchoNet')} + {t("system.sanchoNet")} .
@@ -955,28 +950,30 @@ function useCardano() { />

), - title: t('system.toolConnectedToSanchonet'), - buttonText: t('ok'), + title: t("system.toolConnectedToSanchonet"), + buttonText: t("ok"), }, }); setItemToLocalStorage(`${SANCHO_INFO_KEY}_${walletName}`, true); } return result; } + // TODO: type error + // eslint-disable-next-line @typescript-eslint/no-explicit-any } catch (e: any) { Sentry.captureException(e); await context.disconnectWallet(); navigate(PATHS.home); openModal({ - type: 'statusModal', + type: "statusModal", state: { - status: 'warning', - message: e?.error?.replace('Error: ', ''), + status: "warning", + message: e?.error?.replace("Error: ", ""), onSubmit: () => { closeModal(); }, - title: t('modals.common.oops'), - dataTestId: 'wallet-connection-error-modal', + title: t("modals.common.oops"), + dataTestId: "wallet-connection-error-modal", }, }); throw e; diff --git a/govtool/frontend/src/hooks/forms/useCreateGovernanceActionForm.ts b/govtool/frontend/src/hooks/forms/useCreateGovernanceActionForm.ts index 22843aba7..e8ff4f660 100644 --- a/govtool/frontend/src/hooks/forms/useCreateGovernanceActionForm.ts +++ b/govtool/frontend/src/hooks/forms/useCreateGovernanceActionForm.ts @@ -135,7 +135,7 @@ export const useCreateGovernanceActionForm = ( type: "statusModal", state: { ...storageInformationErrorModals[ - error.message as MetadataHashValidationErrors + error.message as MetadataHashValidationErrors ], onSubmit: backToForm, onCancel: backToDashboard, @@ -183,7 +183,6 @@ export const useCreateGovernanceActionForm = ( } // eslint-disable-next-line @typescript-eslint/no-explicit-any } catch (error: any) { - // eslint-disable-next-line no-console console.error(error); throw error; } diff --git a/govtool/frontend/src/hooks/forms/useRegisterAsdRepForm.tsx b/govtool/frontend/src/hooks/forms/useRegisterAsdRepForm.tsx index 7afe6084a..12d5422d6 100644 --- a/govtool/frontend/src/hooks/forms/useRegisterAsdRepForm.tsx +++ b/govtool/frontend/src/hooks/forms/useRegisterAsdRepForm.tsx @@ -1,11 +1,33 @@ -import { useCallback, useState } from "react"; +import { Dispatch, SetStateAction, useCallback, useState } from "react"; +import { useNavigate } from "react-router-dom"; +import { useTranslation } from "react-i18next"; import { useFormContext } from "react-hook-form"; +import { blake2bHex } from "blakejs"; +import { captureException } from "@sentry/react"; +import { NodeObject } from "jsonld"; + +import { + CIP_100, + CIP_QQQ, + DREP_CONTEXT, + MetadataHashValidationErrors, + PATHS, + storageInformationErrorModals, +} from "@consts"; +import { useCardano, useModal } from "@context"; +import { + canonizeJSON, + downloadJson, + generateJsonld, + validateMetadataHash, +} from "@utils"; +import { useGetVoterInfo } from ".."; export type RegisterAsDRepValues = { bio?: string; dRepName: string; email?: string; - links?: { link: string }[]; + links?: Array<{ link: string }>; storeData?: boolean; storingURL: string; }; @@ -19,11 +41,32 @@ export const defaultRegisterAsDRepValues: RegisterAsDRepValues = { storingURL: "", }; -export const useRegisterAsdRepForm = () => { +export const useRegisterAsdRepForm = ( + setStep?: Dispatch>, +) => { + const { t } = useTranslation(); + const navigate = useNavigate(); const [isLoading, setIsLoading] = useState(false); + const [hash, setHash] = useState(null); + const [json, setJson] = useState(null); + const { closeModal, openModal } = useModal(); + const { buildDRepRegCert, buildDRepUpdateCert, buildSignSubmitConwayCertTx } = + useCardano(); + const { voter } = useGetVoterInfo(); + + const backToForm = useCallback(() => { + setStep?.(3); + closeModal(); + }, [setStep]); + + const backToDashboard = useCallback(() => { + navigate(PATHS.dashboard); + closeModal(); + }, []); const { control, + getValues, handleSubmit, formState: { errors, isValid }, register, @@ -31,24 +74,148 @@ export const useRegisterAsdRepForm = () => { watch, } = useFormContext(); - const onSubmit = useCallback(async (values: RegisterAsDRepValues) => { - try { - // eslint-disable-next-line no-console - console.log(values); - // eslint-disable-next-line @typescript-eslint/no-explicit-any - } catch (e: any) { - // eslint-disable-next-line no-console - console.error(e); - } finally { - setIsLoading(false); - } + const dRepName = watch("dRepName"); + const isError = Object.keys(errors).length > 0; + + const generateMetadata = useCallback(async () => { + const data = getValues(); + const acceptedKeys = ["dRepName", "bio", "email"]; + + const filteredData = Object.entries(data) + .filter(([key]) => acceptedKeys.includes(key)) + .map(([key, value]) => [CIP_QQQ + key, value]); + + const references = (data as RegisterAsDRepValues).links + ?.filter((link) => link.link) + .map((link) => ({ + "@type": "Other", + [`${CIP_100}reference-label`]: "Label", + [`${CIP_100}reference-uri`]: link.link, + })); + + const body = { + ...Object.fromEntries(filteredData), + [`${CIP_QQQ}references`]: references, + }; + + const jsonld = await generateJsonld(body, DREP_CONTEXT, CIP_QQQ); + + const canonizedJson = await canonizeJSON(jsonld); + const canonizedJsonHash = blake2bHex(canonizedJson, undefined, 32); + + setHash(canonizedJsonHash); + setJson(jsonld); + + return jsonld; }, []); + const onClickDownloadJson = async () => { + if (!json) return; + + downloadJson(json, dRepName); + }; + + const validateHash = useCallback( + async (storingUrl: string) => { + try { + if (!hash) throw new Error(MetadataHashValidationErrors.INVALID_HASH); + + await validateMetadataHash(storingUrl, hash); + // eslint-disable-next-line @typescript-eslint/no-explicit-any + } catch (error: any) { + if ( + Object.values(MetadataHashValidationErrors).includes(error.message) + ) { + openModal({ + type: "statusModal", + state: { + ...storageInformationErrorModals[ + error.message as MetadataHashValidationErrors + ], + onSubmit: backToForm, + onCancel: backToDashboard, + // TODO: Open usersnap feedback + onFeedback: backToDashboard, + }, + }); + } + throw error; + } + }, + [backToForm, hash], + ); + + const createRegistrationCert = useCallback( + async (data: RegisterAsDRepValues) => { + if (!hash) return; + const url = data.storingURL; + + try { + if (voter?.isRegisteredAsSoleVoter) { + return await buildDRepUpdateCert(url, hash); + } + + return await buildDRepRegCert(url, hash); + // eslint-disable-next-line @typescript-eslint/no-explicit-any + } catch (error: any) { + console.error(error); + throw error; + } + }, + [ + buildDRepRegCert, + buildDRepUpdateCert, + hash, + voter?.isRegisteredAsSoleVoter, + ], + ); + + const showSuccessModal = useCallback(() => { + openModal({ + type: "statusModal", + state: { + status: "success", + title: t("modals.registration.title"), + message: t("modals.registration.message"), + buttonText: t("modals.common.goToDashboard"), + dataTestId: "governance-action-submitted-modal", + onSubmit: backToDashboard, + }, + }); + }, []); + + const onSubmit = useCallback( + async (data: RegisterAsDRepValues) => { + try { + setIsLoading(true); + + await validateHash(data.storingURL); + const registerAsDRepCert = await createRegistrationCert(data); + await buildSignSubmitConwayCertTx({ + certBuilder: registerAsDRepCert, + type: "registerAsDrep", + }); + + showSuccessModal(); + // eslint-disable-next-line @typescript-eslint/no-explicit-any + } catch (error: any) { + captureException(error); + } finally { + setIsLoading(false); + } + }, + [buildSignSubmitConwayCertTx, createRegistrationCert, hash, validateHash], + ); + return { control, errors, + generateMetadata, + getValues, + isError, isRegistrationAsDRepLoading: isLoading, isValid, + onClickDownloadJson, register, registerAsDrep: handleSubmit(onSubmit), resetField, diff --git a/govtool/frontend/src/hooks/index.ts b/govtool/frontend/src/hooks/index.ts index 84e427cfa..126c2d0c9 100644 --- a/govtool/frontend/src/hooks/index.ts +++ b/govtool/frontend/src/hooks/index.ts @@ -1,8 +1,9 @@ export { useTranslation } from "react-i18next"; +export * from "./useFetchNextPageDetector"; +export * from "./useOutsideClick"; +export * from "./useSaveScrollPosition"; export * from "./useScreenDimension"; export * from "./useSlider"; -export * from "./useSaveScrollPosition"; -export * from "./useFetchNextPageDetector"; export * from "./useWalletConnectionListener"; export * from "./forms"; diff --git a/govtool/frontend/src/hooks/queries/useGetAdaHolderCurrentDelegationQuery.ts b/govtool/frontend/src/hooks/queries/useGetAdaHolderCurrentDelegationQuery.ts index 94dc2621d..ba2b170af 100644 --- a/govtool/frontend/src/hooks/queries/useGetAdaHolderCurrentDelegationQuery.ts +++ b/govtool/frontend/src/hooks/queries/useGetAdaHolderCurrentDelegationQuery.ts @@ -4,13 +4,13 @@ import { getAdaHolderCurrentDelegation } from "@services"; import { QUERY_KEYS } from "@consts"; import { useCardano } from "@context"; -export const useGetAdaHolderCurrentDelegationQuery = (stakeKey?: string) => { +export const useGetAdaHolderCurrentDelegationQuery = (stakeKey: string | undefined) => { const { pendingTransaction } = useCardano(); const { data, isLoading } = useQuery({ queryKey: [ QUERY_KEYS.getAdaHolderCurrentDelegationKey, - pendingTransaction.delegate, + pendingTransaction.delegate?.transactionHash, ], queryFn: () => getAdaHolderCurrentDelegation({ stakeKey }), enabled: !!stakeKey, diff --git a/govtool/frontend/src/hooks/queries/useGetDRepListQuery.ts b/govtool/frontend/src/hooks/queries/useGetDRepListQuery.ts index 4e9aa0c26..806d55072 100644 --- a/govtool/frontend/src/hooks/queries/useGetDRepListQuery.ts +++ b/govtool/frontend/src/hooks/queries/useGetDRepListQuery.ts @@ -10,10 +10,10 @@ export const useGetDRepListQuery = () => { const { data, isLoading } = useQuery({ queryKey: [ QUERY_KEYS.useGetDRepListKey, - pendingTransaction.registerAsSoleVoter || + (pendingTransaction.registerAsSoleVoter || pendingTransaction.registerAsDrep || pendingTransaction.retireAsSoleVoter || - pendingTransaction.retireAsDrep, + pendingTransaction.retireAsDrep)?.transactionHash, ], queryFn: getDRepList, }); diff --git a/govtool/frontend/src/hooks/queries/useGetDRepVotesQuery.ts b/govtool/frontend/src/hooks/queries/useGetDRepVotesQuery.ts index 034423c29..304c39cff 100644 --- a/govtool/frontend/src/hooks/queries/useGetDRepVotesQuery.ts +++ b/govtool/frontend/src/hooks/queries/useGetDRepVotesQuery.ts @@ -11,7 +11,7 @@ export const useGetDRepVotesQuery = (filters: string[], sorting: string) => { const { data, isLoading, refetch, isRefetching } = useQuery({ queryKey: [ QUERY_KEYS.useGetDRepVotesKey, - pendingTransaction.vote, + pendingTransaction.vote?.transactionHash, filters, sorting, ], diff --git a/govtool/frontend/src/hooks/queries/useGetProposalsInfiniteQuery.ts b/govtool/frontend/src/hooks/queries/useGetProposalsInfiniteQuery.ts index 90e2ac016..7e141842e 100644 --- a/govtool/frontend/src/hooks/queries/useGetProposalsInfiniteQuery.ts +++ b/govtool/frontend/src/hooks/queries/useGetProposalsInfiniteQuery.ts @@ -33,7 +33,7 @@ export const useGetProposalsInfiniteQuery = ({ dRepID, filters, isEnabled, - pendingTransaction.vote, + pendingTransaction.vote?.transactionHash, sorting, ], fetchProposals, diff --git a/govtool/frontend/src/hooks/queries/useGetProposalsQuery.ts b/govtool/frontend/src/hooks/queries/useGetProposalsQuery.ts index 3d0434acd..242add713 100644 --- a/govtool/frontend/src/hooks/queries/useGetProposalsQuery.ts +++ b/govtool/frontend/src/hooks/queries/useGetProposalsQuery.ts @@ -28,7 +28,7 @@ export const useGetProposalsQuery = ({ filters, sorting, dRepID, - pendingTransaction.vote, + pendingTransaction.vote?.transactionHash, ], fetchProposals, ); diff --git a/govtool/frontend/src/hooks/queries/useGetVoterInfoQuery.ts b/govtool/frontend/src/hooks/queries/useGetVoterInfoQuery.ts index 5eab75e42..a21a5cf55 100644 --- a/govtool/frontend/src/hooks/queries/useGetVoterInfoQuery.ts +++ b/govtool/frontend/src/hooks/queries/useGetVoterInfoQuery.ts @@ -10,10 +10,10 @@ export const useGetVoterInfo = () => { const { data } = useQuery({ queryKey: [ QUERY_KEYS.useGetDRepInfoKey, - pendingTransaction.registerAsDrep || + (pendingTransaction.registerAsDrep || pendingTransaction.registerAsSoleVoter || pendingTransaction.retireAsDrep || - pendingTransaction.retireAsSoleVoter, + pendingTransaction.retireAsSoleVoter)?.transactionHash, ], enabled: !!dRepID, queryFn: () => getVoterInfo(dRepID), diff --git a/govtool/frontend/src/hooks/useOutsideClick.tsx b/govtool/frontend/src/hooks/useOutsideClick.tsx new file mode 100644 index 000000000..619086632 --- /dev/null +++ b/govtool/frontend/src/hooks/useOutsideClick.tsx @@ -0,0 +1,25 @@ +import { MutableRefObject, useEffect } from "react"; + +export function useOnClickOutside( + ref: MutableRefObject, + handler: (event: MouseEvent | TouchEvent) => void, +) { + useEffect(() => { + const listener = (event: MouseEvent | TouchEvent) => { + const target = event.target as Node; + + if (!ref.current || ref.current.contains(target)) { + return; + } + handler(event); + }; + + document.addEventListener("mousedown", listener as EventListener); + document.addEventListener("touchstart", listener as EventListener); + + return () => { + document.removeEventListener("mousedown", listener as EventListener); + document.removeEventListener("touchstart", listener as EventListener); + }; + }, [ref, handler]); +} diff --git a/govtool/frontend/src/hooks/useSlider.ts b/govtool/frontend/src/hooks/useSlider.ts index 78788791e..b2f64adf5 100644 --- a/govtool/frontend/src/hooks/useSlider.ts +++ b/govtool/frontend/src/hooks/useSlider.ts @@ -1,4 +1,4 @@ -import { ChangeEvent, useState } from "react"; +import { useState } from "react"; import { KeenSliderOptions, useKeenSlider } from "keen-slider/react"; import type { KeenSliderInstance } from "keen-slider"; @@ -47,53 +47,28 @@ const WheelControls = (slider: KeenSliderInstance) => { }); }; -export const useSlider = ({ - config, - sliderMaxLength, -}: { - config: KeenSliderOptions; - sliderMaxLength: number; -}) => { +export const useSlider = ({ config }: { config: KeenSliderOptions }) => { const [currentSlide, setCurrentSlide] = useState(0); - const [currentRange, setCurrentRange] = useState(0); const [sliderRef, instanceRef] = useKeenSlider( { ...config, rubberband: false, detailsChanged: (slider) => { - setCurrentRange(slider.track.details.progress * sliderMaxLength); setCurrentSlide(slider.track.details.rel); }, }, [WheelControls], ); - const DATA_LENGTH = instanceRef?.current?.slides?.length ?? 10; - const ITEMS_PER_VIEW = - DATA_LENGTH - (instanceRef?.current?.track?.details?.maxIdx ?? 2); - - const setPercentageValue = (e: ChangeEvent) => { - const target = e?.target; - const currentIndexOfSlide = Math.floor( - +(target?.value ?? 0) / - (sliderMaxLength / (DATA_LENGTH - Math.floor(ITEMS_PER_VIEW))), - ); - - instanceRef.current?.track.add( - (+(target?.value ?? 0) - currentRange) * - (instanceRef.current.track.details.length / sliderMaxLength), - ); - setCurrentRange(+(target?.value ?? 0)); - setCurrentSlide(currentIndexOfSlide); - }; + const dataLength = instanceRef?.current?.slides?.length ?? 10; + const itemsPerView = + dataLength - (instanceRef?.current?.track?.details?.maxIdx ?? 2); return { sliderRef, instanceRef, currentSlide, - currentRange, - setCurrentRange, - setPercentageValue, + itemsPerView, }; }; diff --git a/govtool/frontend/src/i18n/locales/en.ts b/govtool/frontend/src/i18n/locales/en.ts index f70098f2a..73e9c4217 100644 --- a/govtool/frontend/src/i18n/locales/en.ts +++ b/govtool/frontend/src/i18n/locales/en.ts @@ -199,28 +199,11 @@ export const en = { supportingLinks: "Supporting links", title: "Create a Governance Action", modals: { - externalDataDoesntMatch: { - buttonText: "Go to Data Edit Screen", - cancelRegistrationText: "Cancel Registration", - feedbackText: "Feedback", - message: - "GovTool checks the URL you entered to see if the JSON file that you self-host matches the one that was generated in GovTool. To complete registration, this match must be exact.\n\nIn this case, there is a mismatch. You can go back to the data edit screen and try the process again.", - title: "Your External Data Does Not Match the Original File.", - }, submitTransactionSuccess: { message: "Your Governance Action may take a little time to submit to the chain.", title: "Governance Action submitted!", }, - urlCannotBeFound: { - buttonText: "Go to Data Edit Screen", - cancelRegistrationText: "Cancel Registration", - feedbackText: "Feedback", - linkText: "Learn More about self-hosting", - message: - "GovTool cannot find the URL that you entered. Please check it and re-enter.", - title: "The URL You Entered Cannot Be Found", - }, }, }, delegation: { @@ -260,6 +243,7 @@ export const en = { }, errors: { appCannotCreateTransaction: "Application can not create transaction.", + appCannotGetDeposit: "Can not fetch deposit", appCannotGetUtxos: "Application can not get utxos", appCannotGetVkeys: "Application can not get vkey", checkIsWalletConnected: "Check if the wallet is connected.", @@ -314,28 +298,46 @@ export const en = { }, }, govActions: { + about: "About", + abstract: "Abstract:", + backToGovActions: "Back to Governance Actions", + castVote: "<0>You voted {{vote}} for this proposal\nat {{date}}", + castVoteDeadline: + "You can change your vote up to the deadline of {{date}}", changeVote: "Change vote", changeYourVote: "Change your vote", chooseHowToVote: "Choose how you want to vote:", + dataMissing: "Data Missing", + dataMissingTooltipExplanation: + "Please click “View Details” for more information.", details: "Governance Details:", + expiresDateWithEpoch: "Expires: <0>{{date}} <1>(Epoch {{epoch}})", expiryDate: "Expiry date:", filterTitle: "Governance Action Type", forGovAction: "for this Governance Action", governanceActionId: "Governance Action ID:", governanceActionType: "Governance Action Type:", + motivation: "Motivation", myVote: "My Vote:", noResultsForTheSearch: "No results for the search.", + onChainTransactionDetails: "On-chain Transaction Details", optional: "(optional)", provideContext: "Provide context about your vote", + rationale: "Rationale", + seeExternalData: "See external data", selectDifferentOption: "Select a different option to change your vote", showVotes: "Show votes", submissionDate: "Submission date:", + submittedDateWithEpoch: + "Submitted: <0>{{date}} <1>(Epoch {{epoch}})", + supportingLinks: "Supporting links", title: "Governance Actions", toVote: "To vote", + viewDetails: "View Details", viewOtherDetails: "View other details", viewProposalDetails: "View proposal details", vote: "Vote", - voted: "Voted", + votedOnByMe: "Voted on by me", voteOnGovActions: "Vote on Governance Action", voteSubmitted: "Vote submitted", voteTransaction: "Vote transaction", @@ -420,6 +422,14 @@ export const en = { "The confirmation of your actual delegation might take a bit of time but you can track it using", title: "Delegation Transaction Submitted!", }, + externalDataDoesntMatch: { + buttonText: "Go to Data Edit Screen", + cancelRegistrationText: "Cancel Registration", + feedbackText: "Feedback", + message: + "GovTool checks the URL you entered to see if the JSON file that you self-host matches the one that was generated in GovTool. To complete registration, this match must be exact.\n\nIn this case, there is a mismatch. You can go back to the data edit screen and try the process again.", + title: "Your External Data Does Not Match the Original File.", + }, externalLink: { beCareful: "Be Careful!", continueTo: "Continue to external link", @@ -442,6 +452,15 @@ export const en = { "The confirmation of your retirement might take a bit of time but you can track it using", title: "Retirement Transaction Submitted!", }, + urlCannotBeFound: { + buttonText: "Go to Data Edit Screen", + cancelRegistrationText: "Cancel Registration", + feedbackText: "Feedback", + linkText: "Learn More about self-hosting", + message: + "GovTool cannot find the URL that you entered. Please check it and re-enter.", + title: "The URL You Entered Cannot Be Found", + }, votingPower: { govActionsVotes: "Governance Action votes", votesSubmittedByDReps: "Votes submitted by DReps", @@ -468,7 +487,7 @@ export const en = { "This is the name that will be displayed in the DRep Directory and it will be used also by delegators to find your profile.", headingStepTwo: "Confirm DRep registration", linksDescription: "Links to extra content or social media contacts ", - maximumLinks: "(maximum of 7 entries)", + maximumLinks: "(maximum of {{numberOfLinks}} entries)", optional: "optional", register: "Register", required: "required", @@ -490,13 +509,23 @@ export const en = { storingInformationURLPlaceholder: "URL", fields: { validations: { + email: "Invalid email address", + maxLength: "Max {{maxLength}} characters", + nickname: "Nickname can not contain whitespaces", required: "This field is required", url: "Invalid URL", }, }, }, + retirement: { + continue: "Continue to Retirement", + retireAsDrep: "Retire as a Drep", + whatRetirementMeansTitle: "What Retirement Means", + whatRetirementMeansDescription: + "By retiring you are giving up your voting rights. Voting Power that is delegated to you will remain in place.\n\nADA Holders that have delegated to be able to see that you are retired in the DRep directory. They will be able to re-delegate their Voting Power to another DRep.\n\nYou can still participate in Governance by proposing Governance Actions, by delegating your personal Voting Power to another DRep, or by coming out of retirement, and assuming your previous role as a DRep.\n\nIf you come out of retirement, your DRep ID will be the same as it was before retirement, and your Voting Power will consist of your own ADA balance and what delegated power that remains associated\nto your DRep ID.", + }, slider: { - showAll: "Show all", + showAll: "Show All", viewAll: "View all", }, soleVoter: { @@ -586,11 +615,13 @@ export const en = { backToList: "Back to the list", cancel: "Cancel", clear: "Clear", + clickToCopyLink: "Click to copy link", confirm: "Confirm", continue: "Continue", delegate: "Delegate", + filter: "Filter", here: "here", - inProgress: "In Progress", + inProgress: "In progress", learnMore: "Learn more", loading: "Loading...", myDRepId: "My DRep ID:", @@ -602,7 +633,10 @@ export const en = { required: "required", seeTransaction: "See transaction", select: "Select", + share: "Share", + showMore: "Show more", skip: "Skip", + sort: "Sort", sortBy: "Sort by", submit: "Submit", thisLink: "this link", diff --git a/govtool/frontend/src/pages/DashboardGovernanceActionsCategory.tsx b/govtool/frontend/src/pages/DashboardGovernanceActionsCategory.tsx index 8685bfbf8..47384da36 100644 --- a/govtool/frontend/src/pages/DashboardGovernanceActionsCategory.tsx +++ b/govtool/frontend/src/pages/DashboardGovernanceActionsCategory.tsx @@ -1,19 +1,8 @@ import { useCallback, useMemo, useRef, useState } from "react"; -import { - generatePath, - NavLink, - useNavigate, - useParams, -} from "react-router-dom"; -import { - Box, - Breadcrumbs, - CircularProgress, - Link, - Typography, -} from "@mui/material"; +import { generatePath, useNavigate, useParams } from "react-router-dom"; +import { Box, CircularProgress, Link } from "@mui/material"; -import { Background } from "@atoms"; +import { Background, Typography } from "@atoms"; import { ICONS, PATHS } from "@consts"; import { useCardano } from "@context"; import { DataActionsBar, GovernanceActionCard } from "@molecules"; @@ -68,21 +57,6 @@ export const DashboardGovernanceActionsCategory = () => { isProposalsFetching, ); - const breadcrumbs = [ - - - {t("govActions.title")} - - , - - {getProposalTypeLabel(category ?? "")} - , - ]; - const mappedData = useMemo(() => { const uniqueProposals = removeDuplicatedProposals(proposals); @@ -112,23 +86,13 @@ export const DashboardGovernanceActionsCategory = () => { > - - {breadcrumbs} - navigate(PATHS.dashboardGovernanceActions)} > @@ -137,8 +101,8 @@ export const DashboardGovernanceActionsCategory = () => { alt="arrow" style={{ marginRight: "12px", transform: "rotate(180deg)" }} /> - - {t("backToList")} + + {t("govActions.backToGovActions")} { sortingActive={Boolean(chosenSorting)} sortOpen={sortOpen} /> - + + {getProposalTypeLabel(category ?? "")} + {!mappedData || isEnableLoading || isProposalsLoading ? ( ) : !mappedData?.length ? ( - + {t("govActions.withCategoryNotExist.partOne")}   - {` ${category} `} + + {` ${category} `} +   {t("govActions.withCategoryNotExist.partTwo")} @@ -173,14 +155,11 @@ export const DashboardGovernanceActionsCategory = () => { ) : ( {mappedData.map((item) => ( @@ -189,17 +168,22 @@ export const DashboardGovernanceActionsCategory = () => { index={item.index} inProgress={ pendingTransaction.vote?.resourceId === - item.txHash + item.index + `${item.txHash ?? ""}${item.index ?? ""}` } + // TODO: Add data validation + isDataMissing={false} onClick={() => { saveScrollPosition(); - // eslint-disable-next-line no-unused-expressions - pendingTransaction.vote?.resourceId === item.txHash + item.index - ? openInNewTab( + if ( + pendingTransaction.vote?.resourceId === + item.txHash + item.index + ) { + openInNewTab( "https://adanordic.com/latest_transactions", - ) - : navigate( + ); + } else { + navigate( generatePath( PATHS.dashboardGovernanceActionsAction, { @@ -216,6 +200,7 @@ export const DashboardGovernanceActionsCategory = () => { }, }, ); + } }} txHash={item.txHash} /> diff --git a/govtool/frontend/src/pages/GovernanceActionDetails.tsx b/govtool/frontend/src/pages/GovernanceActionDetails.tsx index 34378488d..c914ce978 100644 --- a/govtool/frontend/src/pages/GovernanceActionDetails.tsx +++ b/govtool/frontend/src/pages/GovernanceActionDetails.tsx @@ -3,10 +3,9 @@ import { useNavigate, useLocation, useParams, - NavLink, generatePath, } from "react-router-dom"; -import { Box, Breadcrumbs, CircularProgress, Link } from "@mui/material"; +import { Box, CircularProgress, Link } from "@mui/material"; import { Background, Typography } from "@atoms"; import { ICONS, PATHS } from "@consts"; @@ -24,11 +23,15 @@ import { getItemFromLocalStorage, getShortenedGovActionId, } from "@utils"; +import { Breadcrumbs } from "@molecules"; + +// TODO: Remove when data validation is ready +const isDataMissing = false; export const GovernanceActionDetails = () => { const { state, hash } = useLocation(); const navigate = useNavigate(); - const { pagePadding, screenWidth } = useScreenDimension(); + const { pagePadding, isMobile } = useScreenDimension(); const { isEnabled } = useCardano(); const { t } = useTranslation(); const { proposalId } = useParams(); @@ -48,21 +51,6 @@ export const GovernanceActionDetails = () => { } }, [isEnabled]); - const breadcrumbs = [ - - - {t("govActions.title")} - - , - - {t("govActions.voteOnGovActions")} - , - ]; - return ( { px={pagePadding} > - {screenWidth >= 1024 ? ( - - {t("govActions.title")} - + {isMobile ? ( + + + {t("govActions.title")} + + ) : null} - {breadcrumbs} - + elementOne={t("govActions.title")} + elementOnePath={PATHS.dashboardGovernanceActions} + elementTwo="Fund our project" + isDataMissing={false} + /> { style={{ marginRight: "12px", transform: "rotate(180deg)" }} /> - {t("backToList")} + {t("back")} {isLoading ? ( @@ -130,11 +124,7 @@ export const GovernanceActionDetails = () => { ) : data || state ? ( - + { ? formatDisplayDate(state.createdDate) : formatDisplayDate(data.proposal.createdDate) } - details={state ? state.details : data.proposal.details} + // TODO: Add data validation + isDataMissing={isDataMissing} expiryDate={ state ? formatDisplayDate(state.expiryDate) @@ -156,9 +147,10 @@ export const GovernanceActionDetails = () => { ? getProposalTypeLabel(state.type) : getProposalTypeLabel(data.proposal.type) } - url={state ? state.url : data.proposal.url} + // TODO: To decide if we want to keep it when metadate BE is ready + // url={state ? state.url : data.proposal.url} yesVotes={state ? state.yesVotes : data.proposal.yesVotes} - shortenedGovActionId={shortenedGovActionId} + govActionId={fullProposalId} /> ) : ( diff --git a/govtool/frontend/src/pages/GovernanceActionsCategory.tsx b/govtool/frontend/src/pages/GovernanceActionsCategory.tsx index e29cbe1c3..82b67ce46 100644 --- a/govtool/frontend/src/pages/GovernanceActionsCategory.tsx +++ b/govtool/frontend/src/pages/GovernanceActionsCategory.tsx @@ -1,12 +1,6 @@ import { useState, useCallback, useEffect, useMemo, useRef } from "react"; -import { NavLink, useNavigate, useParams } from "react-router-dom"; -import { - Box, - Breadcrumbs, - CircularProgress, - Divider, - Link, -} from "@mui/material"; +import { useNavigate, useParams } from "react-router-dom"; +import { Box, CircularProgress, Link } from "@mui/material"; import { Background, Typography } from "@atoms"; import { ICONS, PATHS } from "@consts"; @@ -65,21 +59,6 @@ export const GovernanceActionsCategory = () => { isProposalsFetching, ); - const breadcrumbs = [ - - - {t("govActions.title")} - - , - - {getProposalTypeLabel(category ?? "")} - , - ]; - const mappedData = useMemo(() => { const uniqueProposals = removeDuplicatedProposals(proposals); @@ -116,32 +95,7 @@ export const GovernanceActionsCategory = () => { > - - {t("govActions.title")} - - {isMobile && ( - - )} - - {breadcrumbs} - { alt="arrow" style={{ marginRight: "12px", transform: "rotate(180deg)" }} /> - - {t("backToList")} + + {t("govActions.backToGovActions")} { closeSorts={closeSorts} setChosenSorting={setChosenSorting} /> - + + {getProposalTypeLabel(category ?? "")} + {!isProposalsLoading ? ( !mappedData?.length ? ( @@ -202,14 +163,10 @@ export const GovernanceActionsCategory = () => { ) : ( {mappedData.map((item) => ( @@ -218,6 +175,8 @@ export const GovernanceActionsCategory = () => { {...item} txHash={item.txHash} index={item.index} + // TODO: Add data validation + isDataMissing={false} onClick={() => { saveScrollPosition(); diff --git a/govtool/frontend/src/pages/RetireAsDrep.tsx b/govtool/frontend/src/pages/RetireAsDrep.tsx new file mode 100644 index 000000000..f0349b0f1 --- /dev/null +++ b/govtool/frontend/src/pages/RetireAsDrep.tsx @@ -0,0 +1,44 @@ +import { useEffect } from "react"; +import { useNavigate } from "react-router-dom"; +import { Box } from "@mui/material"; + +import { Background } from "@atoms"; +import { PATHS } from "@consts"; +import { DashboardTopNav, WhatRetirementMeans } from "@organisms"; +import { useScreenDimension, useTranslation } from "@hooks"; +import { LinkWithIcon } from "@molecules"; +import { checkIsWalletConnected } from "@utils"; + +export const RetireAsDrep = () => { + const navigate = useNavigate(); + const { t } = useTranslation(); + const { isMobile } = useScreenDimension(); + + useEffect(() => { + if (checkIsWalletConnected()) { + navigate(PATHS.home); + } + }, []); + + const onClickBackToDashboard = () => navigate(PATHS.dashboard); + + return ( + + + + + + + + ); +}; diff --git a/govtool/frontend/src/pages/index.ts b/govtool/frontend/src/pages/index.ts index c2f422300..3739fa117 100644 --- a/govtool/frontend/src/pages/index.ts +++ b/govtool/frontend/src/pages/index.ts @@ -1,4 +1,5 @@ export * from "./ChooseStakeKey"; +export * from "./CreateGovernanceAction"; export * from "./Dashboard"; export * from "./DashboardGovernanceActionsCategory"; export * from "./DelegateTodRep"; @@ -8,5 +9,7 @@ export * from "./GovernanceActions"; export * from "./GovernanceActionsCategory"; export * from "./Home"; export * from "./RegisterAsdRep"; +export * from "./RegisterAsSoleVoter"; +export * from "./RetireAsDrep"; export * from "./RetireAsSoleVoter"; export * from "./UpdatedRepMetadata"; diff --git a/govtool/frontend/src/stories/GovernanceAction.stories.ts b/govtool/frontend/src/stories/GovernanceAction.stories.ts index 8ed28776b..770b603c0 100644 --- a/govtool/frontend/src/stories/GovernanceAction.stories.ts +++ b/govtool/frontend/src/stories/GovernanceAction.stories.ts @@ -1,58 +1,61 @@ -import type { Meta, StoryObj } from "@storybook/react"; -import { within, userEvent, waitFor, screen } from "@storybook/testing-library"; -import { expect, jest } from "@storybook/jest"; +// Story to be updated when new Gov Actions are finished +/* eslint-disable storybook/default-exports */ -import { formatDisplayDate } from "@utils"; -import { GovernanceActionCard } from "@/components/molecules"; +// import type { Meta, StoryObj } from "@storybook/react"; +// import { within, userEvent, waitFor, screen } from "@storybook/testing-library"; +// import { expect, jest } from "@storybook/jest"; -const meta = { - title: "Example/GovernanceActionCard", - component: GovernanceActionCard, - parameters: { - layout: "centered", - }, - tags: ["autodocs"], -} satisfies Meta; +// import { formatDisplayDate } from "@utils"; +// import { GovernanceActionCard } from "@/components/molecules"; -export default meta; -type Story = StoryObj; +// const meta = { +// title: "Example/GovernanceActionCard", +// component: GovernanceActionCard, +// parameters: { +// layout: "centered", +// }, +// tags: ["autodocs"], +// } satisfies Meta; -export const GovernanceActionCardComponent: Story = { - args: { - createdDate: "1970-01-01T00:00:00Z", - expiryDate: "1970-02-01T00:00:00Z", - type: "exampleType", - txHash: "sad78afdsf7jasd98d", - index: 2, - onClick: jest.fn(), - }, - play: async ({ canvasElement, args }) => { - const canvas = within(canvasElement); - expect(canvas.getByTestId("exampleType-type")).toBeInTheDocument(); - expect(canvas.getByTestId("sad78afdsf7jasd98d#2-id")).toBeInTheDocument(); - expect( - canvas.getByText(formatDisplayDate("1970-01-01T00:00:00Z")), - ).toBeInTheDocument(); - expect( - canvas.getByText(formatDisplayDate("1970-02-01T00:00:00Z")), - ).toBeInTheDocument(); +// export default meta; +// type Story = StoryObj; - const tooltips = canvas.getAllByTestId("InfoOutlinedIcon"); - await userEvent.hover(tooltips[0]); - await waitFor(async () => { - expect(screen.getByRole("tooltip")).toBeInTheDocument(); - expect(screen.getByRole("tooltip")).toHaveTextContent(/Submission Date/i); - await userEvent.unhover(tooltips[0]); - }); - await userEvent.hover(tooltips[1]); - await waitFor(() => { - expect(screen.getByRole("tooltip")).toBeInTheDocument(); - expect(screen.getByRole("tooltip")).toHaveTextContent(/Expiry Date/i); - }); +// export const GovernanceActionCardComponent: Story = { +// args: { +// createdDate: "1970-01-01T00:00:00Z", +// expiryDate: "1970-02-01T00:00:00Z", +// type: "exampleType", +// txHash: "sad78afdsf7jasd98d", +// index: 2, +// onClick: jest.fn(), +// }, +// play: async ({ canvasElement, args }) => { +// const canvas = within(canvasElement); +// expect(canvas.getByTestId("exampleType-type")).toBeInTheDocument(); +// expect(canvas.getByTestId("sad78afdsf7jasd98d#2-id")).toBeInTheDocument(); +// expect( +// canvas.getByText(formatDisplayDate("1970-01-01T00:00:00Z")), +// ).toBeInTheDocument(); +// expect( +// canvas.getByText(formatDisplayDate("1970-02-01T00:00:00Z")), +// ).toBeInTheDocument(); - await userEvent.click( - canvas.getByTestId("govaction-sad78afdsf7jasd98d#2-view-detail"), - ); - await expect(args.onClick).toHaveBeenCalled(); - }, -}; +// const tooltips = canvas.getAllByTestId("InfoOutlinedIcon"); +// await userEvent.hover(tooltips[0]); +// await waitFor(async () => { +// expect(screen.getByRole("tooltip")).toBeInTheDocument(); +// expect(screen.getByRole("tooltip")).toHaveTextContent(/Submission Date/i); +// await userEvent.unhover(tooltips[0]); +// }); +// await userEvent.hover(tooltips[1]); +// await waitFor(() => { +// expect(screen.getByRole("tooltip")).toBeInTheDocument(); +// expect(screen.getByRole("tooltip")).toHaveTextContent(/Expiry Date/i); +// }); + +// await userEvent.click( +// canvas.getByTestId("govaction-sad78afdsf7jasd98d#2-view-detail"), +// ); +// await expect(args.onClick).toHaveBeenCalled(); +// }, +// }; diff --git a/govtool/frontend/src/stories/GovernanceActionDetailsCard.stories.ts b/govtool/frontend/src/stories/GovernanceActionDetailsCard.stories.ts index 8f7d8793d..454db3a52 100644 --- a/govtool/frontend/src/stories/GovernanceActionDetailsCard.stories.ts +++ b/govtool/frontend/src/stories/GovernanceActionDetailsCard.stories.ts @@ -1,62 +1,65 @@ -import type { Meta, StoryObj } from "@storybook/react"; -import { screen, userEvent, waitFor, within } from "@storybook/testing-library"; -import { GovernanceActionDetailsCard } from "@organisms"; -import { expect } from "@storybook/jest"; - -const meta = { - title: "Example/GovernanceActionDetailsCard", - component: GovernanceActionDetailsCard, - parameters: { - layout: "centered", - }, - tags: ["autodocs"], -} satisfies Meta; - -export default meta; -type Story = StoryObj; - -export const GovernanceActionDetailsCardComponent: Story = { - args: { - abstainVotes: 1000000, - createdDate: new Date().toLocaleDateString(), - expiryDate: new Date().toLocaleDateString(), - shortenedGovActionId: "Example id", - noVotes: 1000000, - type: "Gov Type", - url: "https://exampleurl.com", - yesVotes: 1000000, - details: { - key: "value", - key2: ["key-list", "key-list", "key-list"], - }, - }, - - play: async ({ canvasElement }) => { - const canvas = within(canvasElement); - const todayDate = new Date().toLocaleDateString(); - await expect(canvas.getAllByText(todayDate)).toHaveLength(2); - - const tooltips = canvas.getAllByTestId("InfoOutlinedIcon"); - await userEvent.hover(tooltips[0]); - await waitFor(async () => { - await expect(screen.getByRole("tooltip")).toBeInTheDocument(); - await expect(screen.getByRole("tooltip")).toHaveTextContent( - /Submission Date/i, - ); - await userEvent.unhover(tooltips[0]); - }); - await userEvent.hover(tooltips[1]); - - await expect(canvas.getByText("Gov Type")).toBeInTheDocument(); - await expect(canvas.getByText("Example id")).toBeInTheDocument(); - - await expect(canvas.getByText("key: value")).toBeInTheDocument(); - await expect(canvas.getAllByText("key-list")).toHaveLength(3); - - await expect(canvas.getByText(/Yes/i)).toBeInTheDocument(); - await expect(canvas.getByText(/Abstain/i)).toBeInTheDocument(); - await expect(canvas.getByText(/No/i)).toBeInTheDocument(); - - await userEvent.click(canvas.getByTestId("view-other-details-button")); - }, -}; +// Story to be updated when new Gov Actions are finished +/* eslint-disable storybook/default-exports */ + +// import type { Meta, StoryObj } from "@storybook/react"; +// import { screen, userEvent, waitFor, within } from "@storybook/testing-library"; +// import { GovernanceActionDetailsCard } from "@organisms"; +// import { expect } from "@storybook/jest"; + +// const meta = { +// title: "Example/GovernanceActionDetailsCard", +// component: GovernanceActionDetailsCard, +// parameters: { +// layout: "centered", +// }, +// tags: ["autodocs"], +// } satisfies Meta; + +// export default meta; +// type Story = StoryObj; + +// export const GovernanceActionDetailsCardComponent: Story = { +// args: { +// abstainVotes: 1000000, +// createdDate: new Date().toLocaleDateString(), +// expiryDate: new Date().toLocaleDateString(), +// shortenedGovActionId: "Example id", +// noVotes: 1000000, +// type: "Gov Type", +// url: "https://exampleurl.com", +// yesVotes: 1000000, +// details: { +// key: "value", +// key2: ["key-list", "key-list", "key-list"], +// }, +// }, + +// play: async ({ canvasElement }) => { +// const canvas = within(canvasElement); +// const todayDate = new Date().toLocaleDateString(); +// await expect(canvas.getAllByText(todayDate)).toHaveLength(2); + +// const tooltips = canvas.getAllByTestId("InfoOutlinedIcon"); +// await userEvent.hover(tooltips[0]); +// await waitFor(async () => { +// await expect(screen.getByRole("tooltip")).toBeInTheDocument(); +// await expect(screen.getByRole("tooltip")).toHaveTextContent( +// /Submission Date/i, +// ); +// await userEvent.unhover(tooltips[0]); +// }); +// await userEvent.hover(tooltips[1]); + +// await expect(canvas.getByText("Gov Type")).toBeInTheDocument(); +// await expect(canvas.getByText("Example id")).toBeInTheDocument(); + +// await expect(canvas.getByText("key: value")).toBeInTheDocument(); +// await expect(canvas.getAllByText("key-list")).toHaveLength(3); + +// await expect(canvas.getByText(/Yes/i)).toBeInTheDocument(); +// await expect(canvas.getByText(/Abstain/i)).toBeInTheDocument(); +// await expect(canvas.getByText(/No/i)).toBeInTheDocument(); + +// await userEvent.click(canvas.getByTestId("view-other-details-button")); +// }, +// }; diff --git a/govtool/frontend/src/stories/GovernanceActionVoted.stories.ts b/govtool/frontend/src/stories/GovernanceActionVoted.stories.ts index 4fdbc5790..3547562ab 100644 --- a/govtool/frontend/src/stories/GovernanceActionVoted.stories.ts +++ b/govtool/frontend/src/stories/GovernanceActionVoted.stories.ts @@ -1,180 +1,183 @@ -import type { Meta, StoryObj } from "@storybook/react"; +// Story to be updated when new Gov Actions are finished +/* eslint-disable storybook/default-exports */ -import { GovernanceVotedOnCard } from "@molecules"; -import { userEvent, waitFor, within, screen } from "@storybook/testing-library"; -import { expect } from "@storybook/jest"; -import { formatDisplayDate } from "@/utils"; +// import type { Meta, StoryObj } from "@storybook/react"; -const meta = { - title: "Example/GovernanceVotedOnCard", - component: GovernanceVotedOnCard, - parameters: { - layout: "centered", - }, +// import { GovernanceVotedOnCard } from "@molecules"; +// import { userEvent, waitFor, within, screen } from "@storybook/testing-library"; +// import { expect } from "@storybook/jest"; +// import { formatDisplayDate } from "@/utils"; - tags: ["autodocs"], -} satisfies Meta; +// const meta = { +// title: "Example/GovernanceVotedOnCard", +// component: GovernanceVotedOnCard, +// parameters: { +// layout: "centered", +// }, -export default meta; -type Story = StoryObj; +// tags: ["autodocs"], +// } satisfies Meta; -async function checkGovActionVisibility(canvas: ReturnType) { - expect(canvas.getByTestId("exampleType-type")).toBeInTheDocument(); - expect(canvas.getByTestId("exampleHash#1-id")).toBeInTheDocument(); - expect(canvas.getByText(/vote submitted/i)).toBeInTheDocument(); +// export default meta; +// type Story = StoryObj; - expect( - canvas.getByText(formatDisplayDate("1970-01-01T00:00:00Z")), - ).toBeInTheDocument(); - expect( - canvas.getByText(formatDisplayDate("1970-02-01T00:00:00Z")), - ).toBeInTheDocument(); +// async function checkGovActionVisibility(canvas: ReturnType) { +// expect(canvas.getByTestId("exampleType-type")).toBeInTheDocument(); +// expect(canvas.getByTestId("exampleHash#1-id")).toBeInTheDocument(); +// expect(canvas.getByText(/vote submitted/i)).toBeInTheDocument(); - const tooltips = canvas.getAllByTestId("InfoOutlinedIcon"); - await userEvent.hover(tooltips[0]); - await waitFor(async () => { - expect(screen.getByRole("tooltip")).toBeInTheDocument(); - expect(screen.getByRole("tooltip")).toHaveTextContent(/Submission Date/i); - await userEvent.unhover(tooltips[0]); - }); - await userEvent.hover(tooltips[1]); - await waitFor(() => { - expect(screen.getByRole("tooltip")).toBeInTheDocument(); - expect(screen.getByRole("tooltip")).toHaveTextContent(/Expiry Date/i); - }); +// expect( +// canvas.getByText(formatDisplayDate("1970-01-01T00:00:00Z")), +// ).toBeInTheDocument(); +// expect( +// canvas.getByText(formatDisplayDate("1970-02-01T00:00:00Z")), +// ).toBeInTheDocument(); - await expect( - canvas.getByTestId("govaction-exampleHash#1-change-your-vote"), - ).toBeInTheDocument(); -} +// const tooltips = canvas.getAllByTestId("InfoOutlinedIcon"); +// await userEvent.hover(tooltips[0]); +// await waitFor(async () => { +// expect(screen.getByRole("tooltip")).toBeInTheDocument(); +// expect(screen.getByRole("tooltip")).toHaveTextContent(/Submission Date/i); +// await userEvent.unhover(tooltips[0]); +// }); +// await userEvent.hover(tooltips[1]); +// await waitFor(() => { +// expect(screen.getByRole("tooltip")).toBeInTheDocument(); +// expect(screen.getByRole("tooltip")).toHaveTextContent(/Expiry Date/i); +// }); -export const GovernanceVotedOnCardComponent: Story = { - args: { - votedProposal: { - proposal: { - createdDate: "1970-01-01T00:00:00Z", - expiryDate: "1970-02-01T00:00:00Z", - id: "exampleId", - type: "exampleType", - index: 1, - txHash: "exampleHash", - details: "some details", - url: "https://example.com", - metadataHash: "exampleHash", - yesVotes: 1, - noVotes: 0, - abstainVotes: 2, - }, - vote: { - vote: "no", - proposalId: "exampleId", - drepId: "exampleId", - url: "https://example.com", - metadataHash: "exampleHash", - }, - }, - }, - play: async ({ canvasElement }) => { - const canvas = within(canvasElement); - await checkGovActionVisibility(canvas); - }, -}; +// await expect( +// canvas.getByTestId("govaction-exampleHash#1-change-your-vote"), +// ).toBeInTheDocument(); +// } -export const GovernanceVotedOnCardAbstain: Story = { - args: { - votedProposal: { - proposal: { - createdDate: "1970-01-01T00:00:00Z", - expiryDate: "1970-02-01T00:00:00Z", - id: "exampleId", - type: "exampleType", - index: 1, - txHash: "exampleHash", - details: "some details", - url: "https://example.com", - metadataHash: "exampleHash", - yesVotes: 1, - noVotes: 0, - abstainVotes: 2, - }, - vote: { - vote: "abstain", - proposalId: "exampleId", - drepId: "exampleId", - url: "https://example.com", - metadataHash: "exampleHash", - }, - }, - }, - play: async ({ canvasElement }) => { - const canvas = within(canvasElement); - await checkGovActionVisibility(canvas); - expect(canvas.getByText(/abstain/i)).toBeInTheDocument(); - }, -}; +// export const GovernanceVotedOnCardComponent: Story = { +// args: { +// votedProposal: { +// proposal: { +// createdDate: "1970-01-01T00:00:00Z", +// expiryDate: "1970-02-01T00:00:00Z", +// id: "exampleId", +// type: "exampleType", +// index: 1, +// txHash: "exampleHash", +// details: "some details", +// url: "https://example.com", +// metadataHash: "exampleHash", +// yesVotes: 1, +// noVotes: 0, +// abstainVotes: 2, +// }, +// vote: { +// vote: "no", +// proposalId: "exampleId", +// drepId: "exampleId", +// url: "https://example.com", +// metadataHash: "exampleHash", +// }, +// }, +// }, +// play: async ({ canvasElement }) => { +// const canvas = within(canvasElement); +// await checkGovActionVisibility(canvas); +// }, +// }; -export const GovernanceVotedOnCardYes: Story = { - args: { - votedProposal: { - proposal: { - createdDate: "1970-01-01T00:00:00Z", - expiryDate: "1970-02-01T00:00:00Z", - id: "exampleId", - type: "exampleType", - index: 1, - txHash: "exampleHash", - details: "some details", - url: "https://example.com", - metadataHash: "exampleHash", - yesVotes: 1, - noVotes: 0, - abstainVotes: 2, - }, - vote: { - vote: "yes", - proposalId: "exampleId", - drepId: "exampleId", - url: "https://example.com", - metadataHash: "exampleHash", - }, - }, - }, - play: async ({ canvasElement }) => { - const canvas = within(canvasElement); - await checkGovActionVisibility(canvas); - expect(canvas.getByText(/yes/i)).toBeInTheDocument(); - }, -}; +// export const GovernanceVotedOnCardAbstain: Story = { +// args: { +// votedProposal: { +// proposal: { +// createdDate: "1970-01-01T00:00:00Z", +// expiryDate: "1970-02-01T00:00:00Z", +// id: "exampleId", +// type: "exampleType", +// index: 1, +// txHash: "exampleHash", +// details: "some details", +// url: "https://example.com", +// metadataHash: "exampleHash", +// yesVotes: 1, +// noVotes: 0, +// abstainVotes: 2, +// }, +// vote: { +// vote: "abstain", +// proposalId: "exampleId", +// drepId: "exampleId", +// url: "https://example.com", +// metadataHash: "exampleHash", +// }, +// }, +// }, +// play: async ({ canvasElement }) => { +// const canvas = within(canvasElement); +// await checkGovActionVisibility(canvas); +// expect(canvas.getByText(/abstain/i)).toBeInTheDocument(); +// }, +// }; -export const GovernanceVotedOnCardNo: Story = { - args: { - votedProposal: { - proposal: { - createdDate: "1970-01-01T00:00:00Z", - expiryDate: "1970-02-01T00:00:00Z", - id: "exampleId", - type: "exampleType", - index: 1, - txHash: "exampleHash", - details: "some details", - url: "https://example.com", - metadataHash: "exampleHash", - yesVotes: 1, - noVotes: 0, - abstainVotes: 2, - }, - vote: { - vote: "no", - proposalId: "exampleId", - drepId: "exampleId", - url: "https://example.com", - metadataHash: "exampleHash", - }, - }, - }, - play: async ({ canvasElement }) => { - const canvas = within(canvasElement); - await checkGovActionVisibility(canvas); - expect(canvas.getByText(/no/i)).toBeInTheDocument(); - }, -}; +// export const GovernanceVotedOnCardYes: Story = { +// args: { +// votedProposal: { +// proposal: { +// createdDate: "1970-01-01T00:00:00Z", +// expiryDate: "1970-02-01T00:00:00Z", +// id: "exampleId", +// type: "exampleType", +// index: 1, +// txHash: "exampleHash", +// details: "some details", +// url: "https://example.com", +// metadataHash: "exampleHash", +// yesVotes: 1, +// noVotes: 0, +// abstainVotes: 2, +// }, +// vote: { +// vote: "yes", +// proposalId: "exampleId", +// drepId: "exampleId", +// url: "https://example.com", +// metadataHash: "exampleHash", +// }, +// }, +// }, +// play: async ({ canvasElement }) => { +// const canvas = within(canvasElement); +// await checkGovActionVisibility(canvas); +// expect(canvas.getByText(/yes/i)).toBeInTheDocument(); +// }, +// }; + +// export const GovernanceVotedOnCardNo: Story = { +// args: { +// votedProposal: { +// proposal: { +// createdDate: "1970-01-01T00:00:00Z", +// expiryDate: "1970-02-01T00:00:00Z", +// id: "exampleId", +// type: "exampleType", +// index: 1, +// txHash: "exampleHash", +// details: "some details", +// url: "https://example.com", +// metadataHash: "exampleHash", +// yesVotes: 1, +// noVotes: 0, +// abstainVotes: 2, +// }, +// vote: { +// vote: "no", +// proposalId: "exampleId", +// drepId: "exampleId", +// url: "https://example.com", +// metadataHash: "exampleHash", +// }, +// }, +// }, +// play: async ({ canvasElement }) => { +// const canvas = within(canvasElement); +// await checkGovActionVisibility(canvas); +// expect(canvas.getByText(/no/i)).toBeInTheDocument(); +// }, +// }; diff --git a/govtool/frontend/src/theme.ts b/govtool/frontend/src/theme.ts index 8a8736f17..7b9bd2331 100644 --- a/govtool/frontend/src/theme.ts +++ b/govtool/frontend/src/theme.ts @@ -9,6 +9,8 @@ import { successGreen, } from "./consts"; +export type Theme = typeof theme; + export const theme = createTheme({ breakpoints: { values: { @@ -114,8 +116,10 @@ export const theme = createTheme({ palette: { accentOrange: "#F29339", accentYellow: "#F2D9A9", + arcticWhite: "#FBFBFF", boxShadow1: "rgba(0, 18, 61, 0.37)", boxShadow2: "rgba(47, 98, 220, 0.2)", + errorRed: "#9E2323", fadedPurple: "#716E88", highlightBlue: "#C2EFF299", inputRed: "#FAEAEB", diff --git a/govtool/frontend/src/types/@mui.d.ts b/govtool/frontend/src/types/@mui.d.ts index c8ea5da12..e83f05e7e 100644 --- a/govtool/frontend/src/types/@mui.d.ts +++ b/govtool/frontend/src/types/@mui.d.ts @@ -16,8 +16,10 @@ declare module "@mui/material/styles" { interface PaletteOptions extends MuiPalette { accentOrange: string; accentYellow: string; + arcticWhite: string; boxShadow1: string; boxShadow2: string; + errorRed: string; highlightBlue: string; inputRed: string; negativeRed: string; diff --git a/govtool/frontend/src/utils/generateJsonld.ts b/govtool/frontend/src/utils/generateJsonld.ts index e78c30af9..24ba6187f 100644 --- a/govtool/frontend/src/utils/generateJsonld.ts +++ b/govtool/frontend/src/utils/generateJsonld.ts @@ -17,9 +17,10 @@ export const generateJsonld = async < >( body: T, context: C, + bodyCip: string = CIP_108, ) => { const doc = { - [`${CIP_108}body`]: body, + [`${bodyCip}body`]: body, [`${CIP_100}hashAlgorithm`]: "blake2b-256", [`${CIP_100}authors`]: [], }; diff --git a/govtool/frontend/src/utils/getDRepID.ts b/govtool/frontend/src/utils/getDRepID.ts index ccc23d8bd..05561eaf5 100644 --- a/govtool/frontend/src/utils/getDRepID.ts +++ b/govtool/frontend/src/utils/getDRepID.ts @@ -28,7 +28,6 @@ export const getPubDRepID = async (walletApi: CardanoApiWallet) => { dRepIDBech32, }; } catch (err) { - // eslint-disable-next-line no-console console.error(err); return { dRepKey: undefined, diff --git a/govtool/frontend/src/utils/getProposalTypeLabel.ts b/govtool/frontend/src/utils/getProposalTypeLabel.ts index e44f7905c..7a3dcccdc 100644 --- a/govtool/frontend/src/utils/getProposalTypeLabel.ts +++ b/govtool/frontend/src/utils/getProposalTypeLabel.ts @@ -4,3 +4,6 @@ export const getProposalTypeLabel = (type: string) => { const label = GOVERNANCE_ACTIONS_FILTERS.find((i) => i.key === type)?.label; return label || type; }; + +export const getProposalTypeNoEmptySpaces = (type: string) => + getProposalTypeLabel(type).replace(/ /g, ""); diff --git a/govtool/frontend/src/utils/isValidFormat.ts b/govtool/frontend/src/utils/isValidFormat.ts index 67824d6c3..4b4ccafa8 100644 --- a/govtool/frontend/src/utils/isValidFormat.ts +++ b/govtool/frontend/src/utils/isValidFormat.ts @@ -1,6 +1,8 @@ export const URL_REGEX = /^(?!.*\s)(ipfs:\/\/[a-zA-Z0-9]+|https?:\/\/(?:\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}|[^/\s]+?\.[a-zA-Z]{2,})[^\s]*)/; export const HASH_REGEX = /^[0-9A-Fa-f]+$/; +export const EMAIL_REGEX = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; +export const NICKNAME_REGEX = /^\S+$/; export function isValidURLFormat(str: string) { if (!str.length) return true; diff --git a/govtool/frontend/src/utils/tests/getProposalTypeNoEmptySpaces.test.ts b/govtool/frontend/src/utils/tests/getProposalTypeNoEmptySpaces.test.ts new file mode 100644 index 000000000..4ec64fe92 --- /dev/null +++ b/govtool/frontend/src/utils/tests/getProposalTypeNoEmptySpaces.test.ts @@ -0,0 +1,25 @@ +import { getProposalTypeNoEmptySpaces } from ".."; + +describe("getProposalTypeNoEmptySpaces", () => { + it("returns correct label with no spaces for a known type", () => { + const type = "NoConfidence"; + const expectedLabel = "NoConfidence"; + expect(getProposalTypeNoEmptySpaces(type)).toBe(expectedLabel); + }); + + it("returns correct label with no spaces for another known type", () => { + const type = "ParameterChange"; + const expectedLabel = "ProtocolParameterChanges"; + expect(getProposalTypeNoEmptySpaces(type)).toBe(expectedLabel); + }); + + it("returns the type itself with no spaces removed when no matching key is found", () => { + const type = "UnknownType"; + expect(getProposalTypeNoEmptySpaces(type)).toBe(type); + }); + + it("returns an empty string when given an empty string", () => { + const type = ""; + expect(getProposalTypeNoEmptySpaces(type)).toBe(type); + }); +}); diff --git a/govtool/frontend/yarn.lock b/govtool/frontend/yarn.lock index f5f7feba5..19855528f 100644 --- a/govtool/frontend/yarn.lock +++ b/govtool/frontend/yarn.lock @@ -40,7 +40,7 @@ resolved "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.23.5.tgz" integrity sha512-uU27kfDRlhfKl+w1U6vp16IuvSLtjAxdArVXPa9BvLkrr7CYIsxH5adpHObeAGY/41+syctUWOZ140a2Rvkgjw== -"@babel/core@^7.0.0", "@babel/core@^7.0.0-0", "@babel/core@^7.0.0-0 || ^8.0.0-0 <8.0.0", "@babel/core@^7.11.6", "@babel/core@^7.12.0", "@babel/core@^7.12.3", "@babel/core@^7.13.0", "@babel/core@^7.18.9", "@babel/core@^7.20.12", "@babel/core@^7.22.5", "@babel/core@^7.23.0", "@babel/core@^7.23.2", "@babel/core@^7.23.5", "@babel/core@^7.4.0 || ^8.0.0-0 <8.0.0", "@babel/core@^7.7.5", "@babel/core@^7.8.0": +"@babel/core@^7.11.6", "@babel/core@^7.12.3", "@babel/core@^7.18.9", "@babel/core@^7.20.12", "@babel/core@^7.22.5", "@babel/core@^7.23.0", "@babel/core@^7.23.2", "@babel/core@^7.23.5", "@babel/core@^7.7.5": version "7.23.5" resolved "https://registry.npmjs.org/@babel/core/-/core-7.23.5.tgz" integrity sha512-Cwc2XjUrG4ilcfOw4wBAK+enbdgwAcAJCfGUItPBKR7Mjw4aEfAFYrLxeRp4jWgtNIKn3n2AlBOfwwafl+42/g== @@ -878,7 +878,7 @@ "@babel/helper-create-regexp-features-plugin" "^7.22.15" "@babel/helper-plugin-utils" "^7.22.5" -"@babel/preset-env@^7.1.6", "@babel/preset-env@^7.23.2": +"@babel/preset-env@^7.23.2": version "7.23.5" resolved "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.23.5.tgz" integrity sha512-0d/uxVD6tFGWXGDSfyMD1p2otoaKmu6+GD+NfAx0tMaH+dxORnp7T9TaVQ6mKyya7iBtCIVxHjWT7MuzzM9z+A== @@ -1131,7 +1131,7 @@ resolved "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.8.1.tgz" integrity sha512-W2P2c/VRW1/1tLox0mVUalvnWXxavmv/Oum2aPsRcoDJuob75FC3Y8FbpfLwUegRcxINtGUMPq0tFCvYNTBXNA== -"@emotion/react@^11.0.0-rc.0", "@emotion/react@^11.11.1", "@emotion/react@^11.4.1", "@emotion/react@^11.5.0": +"@emotion/react@^11.11.1": version "11.11.1" resolved "https://registry.npmjs.org/@emotion/react/-/react-11.11.1.tgz" integrity sha512-5mlW1DquU5HaxjLkfkGN1GA/fvVGdyHURRiX/0FHl2cfIfRxSOfmxEH5YS43edp0OldZrZ+dkBKbngxcNCdZvA== @@ -1161,7 +1161,7 @@ resolved "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.2.2.tgz" integrity sha512-0QBtGvaqtWi+nx6doRwDdBIzhNdZrXUppvTM4dtZZWEGTXL/XE/yJxLMGlDT1Gt+UHH5IX1n+jkXyytE/av7OA== -"@emotion/styled@^11.11.0", "@emotion/styled@^11.3.0": +"@emotion/styled@^11.11.0": version "11.11.0" resolved "https://registry.npmjs.org/@emotion/styled/-/styled-11.11.0.tgz" integrity sha512-hM5Nnvu9P3midq5aaXj4I+lnSfNi7Pmd4EWk1fOZ3pxookaQTNew6bp4JaCBYM4HVFZF9g7UjJmsUmC2JlxOng== @@ -1198,6 +1198,56 @@ resolved "https://registry.npmjs.org/@emurgo/cardano-serialization-lib-asmjs/-/cardano-serialization-lib-asmjs-12.0.0-alpha.19.tgz" integrity sha512-fF3e5qPgJeYDDmPVcyZ7nCuqYI6H3JJ5cSjxnKRRKK/FzYxEsHRoxpLCuZ604A4j/4mYNXVlUYeV4KhgecgUBw== +"@esbuild/aix-ppc64@0.19.11": + version "0.19.11" + resolved "https://registry.yarnpkg.com/@esbuild/aix-ppc64/-/aix-ppc64-0.19.11.tgz#2acd20be6d4f0458bc8c784103495ff24f13b1d3" + integrity sha512-FnzU0LyE3ySQk7UntJO4+qIiQgI7KoODnZg5xzXIrFJlKd2P2gwHsHY4927xj9y5PJmJSzULiUCWmv7iWnNa7g== + +"@esbuild/android-arm64@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.18.20.tgz#984b4f9c8d0377443cc2dfcef266d02244593622" + integrity sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ== + +"@esbuild/android-arm64@0.19.11": + version "0.19.11" + resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.19.11.tgz#b45d000017385c9051a4f03e17078abb935be220" + integrity sha512-aiu7K/5JnLj//KOnOfEZ0D90obUkRzDMyqd/wNAUQ34m4YUPVhRZpnqKV9uqDGxT7cToSDnIHsGooyIczu9T+Q== + +"@esbuild/android-arm64@0.19.8": + version "0.19.8" + resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.19.8.tgz#fb7130103835b6d43ea499c3f30cfb2b2ed58456" + integrity sha512-B8JbS61bEunhfx8kasogFENgQfr/dIp+ggYXwTqdbMAgGDhRa3AaPpQMuQU0rNxDLECj6FhDzk1cF9WHMVwrtA== + +"@esbuild/android-arm@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.18.20.tgz#fedb265bc3a589c84cc11f810804f234947c3682" + integrity sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw== + +"@esbuild/android-arm@0.19.11": + version "0.19.11" + resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.19.11.tgz#f46f55414e1c3614ac682b29977792131238164c" + integrity sha512-5OVapq0ClabvKvQ58Bws8+wkLCV+Rxg7tUVbo9xu034Nm536QTII4YzhaFriQ7rMrorfnFKUsArD2lqKbFY4vw== + +"@esbuild/android-arm@0.19.8": + version "0.19.8" + resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.19.8.tgz#b46e4d9e984e6d6db6c4224d72c86b7757e35bcb" + integrity sha512-31E2lxlGM1KEfivQl8Yf5aYU/mflz9g06H6S15ITUFQueMFtFjESRMoDSkvMo8thYvLBax+VKTPlpnx+sPicOA== + +"@esbuild/android-x64@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.18.20.tgz#35cf419c4cfc8babe8893d296cd990e9e9f756f2" + integrity sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg== + +"@esbuild/android-x64@0.19.11": + version "0.19.11" + resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.19.11.tgz#bfc01e91740b82011ef503c48f548950824922b2" + integrity sha512-eccxjlfGw43WYoY9QgB82SgGgDbibcqyDTlk3l3C0jOVHKxrjdc9CTwDUQd0vkvYg5um0OH+GpxYvp39r+IPOg== + +"@esbuild/android-x64@0.19.8": + version "0.19.8" + resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.19.8.tgz#a13db9441b5a4f4e4fec4a6f8ffacfea07888db7" + integrity sha512-rdqqYfRIn4jWOp+lzQttYMa2Xar3OK9Yt2fhOhzFXqg0rVWEfSclJvZq5fZslnz6ypHvVf3CT7qyf0A5pM682A== + "@esbuild/darwin-arm64@0.18.20": version "0.18.20" resolved "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.18.20.tgz" @@ -1213,6 +1263,276 @@ resolved "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.19.8.tgz" integrity sha512-RQw9DemMbIq35Bprbboyf8SmOr4UXsRVxJ97LgB55VKKeJOOdvsIPy0nFyF2l8U+h4PtBx/1kRf0BelOYCiQcw== +"@esbuild/darwin-x64@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.18.20.tgz#d70d5790d8bf475556b67d0f8b7c5bdff053d85d" + integrity sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ== + +"@esbuild/darwin-x64@0.19.11": + version "0.19.11" + resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.19.11.tgz#62f3819eff7e4ddc656b7c6815a31cf9a1e7d98e" + integrity sha512-fkFUiS6IUK9WYUO/+22omwetaSNl5/A8giXvQlcinLIjVkxwTLSktbF5f/kJMftM2MJp9+fXqZ5ezS7+SALp4g== + +"@esbuild/darwin-x64@0.19.8": + version "0.19.8" + resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.19.8.tgz#75c5c88371eea4bfc1f9ecfd0e75104c74a481ac" + integrity sha512-3sur80OT9YdeZwIVgERAysAbwncom7b4bCI2XKLjMfPymTud7e/oY4y+ci1XVp5TfQp/bppn7xLw1n/oSQY3/Q== + +"@esbuild/freebsd-arm64@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.18.20.tgz#98755cd12707f93f210e2494d6a4b51b96977f54" + integrity sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw== + +"@esbuild/freebsd-arm64@0.19.11": + version "0.19.11" + resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.19.11.tgz#d478b4195aa3ca44160272dab85ef8baf4175b4a" + integrity sha512-lhoSp5K6bxKRNdXUtHoNc5HhbXVCS8V0iZmDvyWvYq9S5WSfTIHU2UGjcGt7UeS6iEYp9eeymIl5mJBn0yiuxA== + +"@esbuild/freebsd-arm64@0.19.8": + version "0.19.8" + resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.19.8.tgz#9d7259fea4fd2b5f7437b52b542816e89d7c8575" + integrity sha512-WAnPJSDattvS/XtPCTj1tPoTxERjcTpH6HsMr6ujTT+X6rylVe8ggxk8pVxzf5U1wh5sPODpawNicF5ta/9Tmw== + +"@esbuild/freebsd-x64@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.18.20.tgz#c1eb2bff03915f87c29cece4c1a7fa1f423b066e" + integrity sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ== + +"@esbuild/freebsd-x64@0.19.11": + version "0.19.11" + resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.19.11.tgz#7bdcc1917409178257ca6a1a27fe06e797ec18a2" + integrity sha512-JkUqn44AffGXitVI6/AbQdoYAq0TEullFdqcMY/PCUZ36xJ9ZJRtQabzMA+Vi7r78+25ZIBosLTOKnUXBSi1Kw== + +"@esbuild/freebsd-x64@0.19.8": + version "0.19.8" + resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.19.8.tgz#abac03e1c4c7c75ee8add6d76ec592f46dbb39e3" + integrity sha512-ICvZyOplIjmmhjd6mxi+zxSdpPTKFfyPPQMQTK/w+8eNK6WV01AjIztJALDtwNNfFhfZLux0tZLC+U9nSyA5Zg== + +"@esbuild/linux-arm64@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.18.20.tgz#bad4238bd8f4fc25b5a021280c770ab5fc3a02a0" + integrity sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA== + +"@esbuild/linux-arm64@0.19.11": + version "0.19.11" + resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.19.11.tgz#58ad4ff11685fcc735d7ff4ca759ab18fcfe4545" + integrity sha512-LneLg3ypEeveBSMuoa0kwMpCGmpu8XQUh+mL8XXwoYZ6Be2qBnVtcDI5azSvh7vioMDhoJFZzp9GWp9IWpYoUg== + +"@esbuild/linux-arm64@0.19.8": + version "0.19.8" + resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.19.8.tgz#c577932cf4feeaa43cb9cec27b89cbe0df7d9098" + integrity sha512-z1zMZivxDLHWnyGOctT9JP70h0beY54xDDDJt4VpTX+iwA77IFsE1vCXWmprajJGa+ZYSqkSbRQ4eyLCpCmiCQ== + +"@esbuild/linux-arm@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.18.20.tgz#3e617c61f33508a27150ee417543c8ab5acc73b0" + integrity sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg== + +"@esbuild/linux-arm@0.19.11": + version "0.19.11" + resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.19.11.tgz#ce82246d873b5534d34de1e5c1b33026f35e60e3" + integrity sha512-3CRkr9+vCV2XJbjwgzjPtO8T0SZUmRZla+UL1jw+XqHZPkPgZiyWvbDvl9rqAN8Zl7qJF0O/9ycMtjU67HN9/Q== + +"@esbuild/linux-arm@0.19.8": + version "0.19.8" + resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.19.8.tgz#d6014d8b98b5cbc96b95dad3d14d75bb364fdc0f" + integrity sha512-H4vmI5PYqSvosPaTJuEppU9oz1dq2A7Mr2vyg5TF9Ga+3+MGgBdGzcyBP7qK9MrwFQZlvNyJrvz6GuCaj3OukQ== + +"@esbuild/linux-ia32@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.18.20.tgz#699391cccba9aee6019b7f9892eb99219f1570a7" + integrity sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA== + +"@esbuild/linux-ia32@0.19.11": + version "0.19.11" + resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.19.11.tgz#cbae1f313209affc74b80f4390c4c35c6ab83fa4" + integrity sha512-caHy++CsD8Bgq2V5CodbJjFPEiDPq8JJmBdeyZ8GWVQMjRD0sU548nNdwPNvKjVpamYYVL40AORekgfIubwHoA== + +"@esbuild/linux-ia32@0.19.8": + version "0.19.8" + resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.19.8.tgz#2379a0554307d19ac4a6cdc15b08f0ea28e7a40d" + integrity sha512-1a8suQiFJmZz1khm/rDglOc8lavtzEMRo0v6WhPgxkrjcU0LkHj+TwBrALwoz/OtMExvsqbbMI0ChyelKabSvQ== + +"@esbuild/linux-loong64@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.18.20.tgz#e6fccb7aac178dd2ffb9860465ac89d7f23b977d" + integrity sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg== + +"@esbuild/linux-loong64@0.19.11": + version "0.19.11" + resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.19.11.tgz#5f32aead1c3ec8f4cccdb7ed08b166224d4e9121" + integrity sha512-ppZSSLVpPrwHccvC6nQVZaSHlFsvCQyjnvirnVjbKSHuE5N24Yl8F3UwYUUR1UEPaFObGD2tSvVKbvR+uT1Nrg== + +"@esbuild/linux-loong64@0.19.8": + version "0.19.8" + resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.19.8.tgz#e2a5bbffe15748b49356a6cd7b2d5bf60c5a7123" + integrity sha512-fHZWS2JJxnXt1uYJsDv9+b60WCc2RlvVAy1F76qOLtXRO+H4mjt3Tr6MJ5l7Q78X8KgCFudnTuiQRBhULUyBKQ== + +"@esbuild/linux-mips64el@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.18.20.tgz#eeff3a937de9c2310de30622a957ad1bd9183231" + integrity sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ== + +"@esbuild/linux-mips64el@0.19.11": + version "0.19.11" + resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.19.11.tgz#38eecf1cbb8c36a616261de858b3c10d03419af9" + integrity sha512-B5x9j0OgjG+v1dF2DkH34lr+7Gmv0kzX6/V0afF41FkPMMqaQ77pH7CrhWeR22aEeHKaeZVtZ6yFwlxOKPVFyg== + +"@esbuild/linux-mips64el@0.19.8": + version "0.19.8" + resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.19.8.tgz#1359331e6f6214f26f4b08db9b9df661c57cfa24" + integrity sha512-Wy/z0EL5qZYLX66dVnEg9riiwls5IYnziwuju2oUiuxVc+/edvqXa04qNtbrs0Ukatg5HEzqT94Zs7J207dN5Q== + +"@esbuild/linux-ppc64@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.18.20.tgz#2f7156bde20b01527993e6881435ad79ba9599fb" + integrity sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA== + +"@esbuild/linux-ppc64@0.19.11": + version "0.19.11" + resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.19.11.tgz#9c5725a94e6ec15b93195e5a6afb821628afd912" + integrity sha512-MHrZYLeCG8vXblMetWyttkdVRjQlQUb/oMgBNurVEnhj4YWOr4G5lmBfZjHYQHHN0g6yDmCAQRR8MUHldvvRDA== + +"@esbuild/linux-ppc64@0.19.8": + version "0.19.8" + resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.19.8.tgz#9ba436addc1646dc89dae48c62d3e951ffe70951" + integrity sha512-ETaW6245wK23YIEufhMQ3HSeHO7NgsLx8gygBVldRHKhOlD1oNeNy/P67mIh1zPn2Hr2HLieQrt6tWrVwuqrxg== + +"@esbuild/linux-riscv64@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.18.20.tgz#6628389f210123d8b4743045af8caa7d4ddfc7a6" + integrity sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A== + +"@esbuild/linux-riscv64@0.19.11": + version "0.19.11" + resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.19.11.tgz#2dc4486d474a2a62bbe5870522a9a600e2acb916" + integrity sha512-f3DY++t94uVg141dozDu4CCUkYW+09rWtaWfnb3bqe4w5NqmZd6nPVBm+qbz7WaHZCoqXqHz5p6CM6qv3qnSSQ== + +"@esbuild/linux-riscv64@0.19.8": + version "0.19.8" + resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.19.8.tgz#fbcf0c3a0b20f40b5fc31c3b7695f0769f9de66b" + integrity sha512-T2DRQk55SgoleTP+DtPlMrxi/5r9AeFgkhkZ/B0ap99zmxtxdOixOMI570VjdRCs9pE4Wdkz7JYrsPvsl7eESg== + +"@esbuild/linux-s390x@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.18.20.tgz#255e81fb289b101026131858ab99fba63dcf0071" + integrity sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ== + +"@esbuild/linux-s390x@0.19.11": + version "0.19.11" + resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.19.11.tgz#4ad8567df48f7dd4c71ec5b1753b6f37561a65a8" + integrity sha512-A5xdUoyWJHMMlcSMcPGVLzYzpcY8QP1RtYzX5/bS4dvjBGVxdhuiYyFwp7z74ocV7WDc0n1harxmpq2ePOjI0Q== + +"@esbuild/linux-s390x@0.19.8": + version "0.19.8" + resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.19.8.tgz#989e8a05f7792d139d5564ffa7ff898ac6f20a4a" + integrity sha512-NPxbdmmo3Bk7mbNeHmcCd7R7fptJaczPYBaELk6NcXxy7HLNyWwCyDJ/Xx+/YcNH7Im5dHdx9gZ5xIwyliQCbg== + +"@esbuild/linux-x64@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.18.20.tgz#c7690b3417af318a9b6f96df3031a8865176d338" + integrity sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w== + +"@esbuild/linux-x64@0.19.11": + version "0.19.11" + resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.19.11.tgz#b7390c4d5184f203ebe7ddaedf073df82a658766" + integrity sha512-grbyMlVCvJSfxFQUndw5mCtWs5LO1gUlwP4CDi4iJBbVpZcqLVT29FxgGuBJGSzyOxotFG4LoO5X+M1350zmPA== + +"@esbuild/linux-x64@0.19.8": + version "0.19.8" + resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.19.8.tgz#b187295393a59323397fe5ff51e769ec4e72212b" + integrity sha512-lytMAVOM3b1gPypL2TRmZ5rnXl7+6IIk8uB3eLsV1JwcizuolblXRrc5ShPrO9ls/b+RTp+E6gbsuLWHWi2zGg== + +"@esbuild/netbsd-x64@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.18.20.tgz#30e8cd8a3dded63975e2df2438ca109601ebe0d1" + integrity sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A== + +"@esbuild/netbsd-x64@0.19.11": + version "0.19.11" + resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.19.11.tgz#d633c09492a1721377f3bccedb2d821b911e813d" + integrity sha512-13jvrQZJc3P230OhU8xgwUnDeuC/9egsjTkXN49b3GcS5BKvJqZn86aGM8W9pd14Kd+u7HuFBMVtrNGhh6fHEQ== + +"@esbuild/netbsd-x64@0.19.8": + version "0.19.8" + resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.19.8.tgz#c1ec0e24ea82313cb1c7bae176bd5acd5bde7137" + integrity sha512-hvWVo2VsXz/8NVt1UhLzxwAfo5sioj92uo0bCfLibB0xlOmimU/DeAEsQILlBQvkhrGjamP0/el5HU76HAitGw== + +"@esbuild/openbsd-x64@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.18.20.tgz#7812af31b205055874c8082ea9cf9ab0da6217ae" + integrity sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg== + +"@esbuild/openbsd-x64@0.19.11": + version "0.19.11" + resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.19.11.tgz#17388c76e2f01125bf831a68c03a7ffccb65d1a2" + integrity sha512-ysyOGZuTp6SNKPE11INDUeFVVQFrhcNDVUgSQVDzqsqX38DjhPEPATpid04LCoUr2WXhQTEZ8ct/EgJCUDpyNw== + +"@esbuild/openbsd-x64@0.19.8": + version "0.19.8" + resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.19.8.tgz#0c5b696ac66c6d70cf9ee17073a581a28af9e18d" + integrity sha512-/7Y7u77rdvmGTxR83PgaSvSBJCC2L3Kb1M/+dmSIvRvQPXXCuC97QAwMugBNG0yGcbEGfFBH7ojPzAOxfGNkwQ== + +"@esbuild/sunos-x64@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.18.20.tgz#d5c275c3b4e73c9b0ecd38d1ca62c020f887ab9d" + integrity sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ== + +"@esbuild/sunos-x64@0.19.11": + version "0.19.11" + resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.19.11.tgz#e320636f00bb9f4fdf3a80e548cb743370d41767" + integrity sha512-Hf+Sad9nVwvtxy4DXCZQqLpgmRTQqyFyhT3bZ4F2XlJCjxGmRFF0Shwn9rzhOYRB61w9VMXUkxlBy56dk9JJiQ== + +"@esbuild/sunos-x64@0.19.8": + version "0.19.8" + resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.19.8.tgz#2a697e1f77926ff09fcc457d8f29916d6cd48fb1" + integrity sha512-9Lc4s7Oi98GqFA4HzA/W2JHIYfnXbUYgekUP/Sm4BG9sfLjyv6GKKHKKVs83SMicBF2JwAX6A1PuOLMqpD001w== + +"@esbuild/win32-arm64@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.18.20.tgz#73bc7f5a9f8a77805f357fab97f290d0e4820ac9" + integrity sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg== + +"@esbuild/win32-arm64@0.19.11": + version "0.19.11" + resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.19.11.tgz#c778b45a496e90b6fc373e2a2bb072f1441fe0ee" + integrity sha512-0P58Sbi0LctOMOQbpEOvOL44Ne0sqbS0XWHMvvrg6NE5jQ1xguCSSw9jQeUk2lfrXYsKDdOe6K+oZiwKPilYPQ== + +"@esbuild/win32-arm64@0.19.8": + version "0.19.8" + resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.19.8.tgz#ec029e62a2fca8c071842ecb1bc5c2dd20b066f1" + integrity sha512-rq6WzBGjSzihI9deW3fC2Gqiak68+b7qo5/3kmB6Gvbh/NYPA0sJhrnp7wgV4bNwjqM+R2AApXGxMO7ZoGhIJg== + +"@esbuild/win32-ia32@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.18.20.tgz#ec93cbf0ef1085cc12e71e0d661d20569ff42102" + integrity sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g== + +"@esbuild/win32-ia32@0.19.11": + version "0.19.11" + resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.19.11.tgz#481a65fee2e5cce74ec44823e6b09ecedcc5194c" + integrity sha512-6YOrWS+sDJDmshdBIQU+Uoyh7pQKrdykdefC1avn76ss5c+RN6gut3LZA4E2cH5xUEp5/cA0+YxRaVtRAb0xBg== + +"@esbuild/win32-ia32@0.19.8": + version "0.19.8" + resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.19.8.tgz#cbb9a3146bde64dc15543e48afe418c7a3214851" + integrity sha512-AIAbverbg5jMvJznYiGhrd3sumfwWs8572mIJL5NQjJa06P8KfCPWZQ0NwZbPQnbQi9OWSZhFVSUWjjIrn4hSw== + +"@esbuild/win32-x64@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.18.20.tgz#786c5f41f043b07afb1af37683d7c33668858f6d" + integrity sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ== + +"@esbuild/win32-x64@0.19.11": + version "0.19.11" + resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.19.11.tgz#a5d300008960bb39677c46bf16f53ec70d8dee04" + integrity sha512-vfkhltrjCAb603XaFhqhAF4LGDi2M4OrCRrFusyQ+iTLQ/o60QQXxc9cZC/FFpihBI9N1Grn6SMKVJ4KP7Fuiw== + +"@esbuild/win32-x64@0.19.8": + version "0.19.8" + resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.19.8.tgz#c8285183dbdb17008578dbacb6e22748709b4822" + integrity sha512-bfZ0cQ1uZs2PqpulNL5j/3w+GDhP36k1K5c38QdQg+Swy51jFZWWeIkteNsufkQxp986wnqRRsb/bHbY1WQ7TA== + "@eslint-community/eslint-utils@^4.2.0", "@eslint-community/eslint-utils@^4.4.0": version "4.4.0" resolved "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz" @@ -1436,7 +1756,7 @@ jest-mock "^29.7.0" jest-util "^29.7.0" -"@jest/globals@^29.7.0", "@jest/globals@>= 28": +"@jest/globals@^29.7.0": version "29.7.0" resolved "https://registry.npmjs.org/@jest/globals/-/globals-29.7.0.tgz" integrity sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ== @@ -1654,7 +1974,7 @@ dependencies: "@babel/runtime" "^7.23.4" -"@mui/material@^5.0.0", "@mui/material@^5.14.4": +"@mui/material@^5.14.4": version "5.14.20" resolved "https://registry.npmjs.org/@mui/material/-/material-5.14.20.tgz" integrity sha512-SUcPZnN6e0h1AtrDktEl76Dsyo/7pyEUQ+SAVe9XhHg/iliA0b4Vo+Eg4HbNkELsMbpDsUF4WHp7rgflPG7qYQ== @@ -1737,7 +2057,7 @@ "@nodelib/fs.stat" "2.0.5" run-parallel "^1.1.9" -"@nodelib/fs.stat@^2.0.2", "@nodelib/fs.stat@2.0.5": +"@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2": version "2.0.5" resolved "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz" integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== @@ -2069,11 +2389,76 @@ estree-walker "^2.0.2" picomatch "^2.3.1" +"@rollup/rollup-android-arm-eabi@4.9.2": + version "4.9.2" + resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.9.2.tgz#ccb02257556bacbc1e756ab9b0b973cea2c7a664" + integrity sha512-RKzxFxBHq9ysZ83fn8Iduv3A283K7zPPYuhL/z9CQuyFrjwpErJx0h4aeb/bnJ+q29GRLgJpY66ceQ/Wcsn3wA== + +"@rollup/rollup-android-arm64@4.9.2": + version "4.9.2" + resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.9.2.tgz#21bd0fbafdf442c6a17645b840f6a94556b0e9bb" + integrity sha512-yZ+MUbnwf3SHNWQKJyWh88ii2HbuHCFQnAYTeeO1Nb8SyEiWASEi5dQUygt3ClHWtA9My9RQAYkjvrsZ0WK8Xg== + "@rollup/rollup-darwin-arm64@4.9.2": version "4.9.2" resolved "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.9.2.tgz" integrity sha512-vqJ/pAUh95FLc/G/3+xPqlSBgilPnauVf2EXOQCZzhZJCXDXt/5A8mH/OzU6iWhb3CNk5hPJrh8pqJUPldN5zw== +"@rollup/rollup-darwin-x64@4.9.2": + version "4.9.2" + resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.9.2.tgz#1b06291ff1c41af94d2786cd167188c5bf7caec9" + integrity sha512-otPHsN5LlvedOprd3SdfrRNhOahhVBwJpepVKUN58L0RnC29vOAej1vMEaVU6DadnpjivVsNTM5eNt0CcwTahw== + +"@rollup/rollup-linux-arm-gnueabihf@4.9.2": + version "4.9.2" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.9.2.tgz#147069948bba00f435122f411210624e72638ebf" + integrity sha512-ewG5yJSp+zYKBYQLbd1CUA7b1lSfIdo9zJShNTyc2ZP1rcPrqyZcNlsHgs7v1zhgfdS+kW0p5frc0aVqhZCiYQ== + +"@rollup/rollup-linux-arm64-gnu@4.9.2": + version "4.9.2" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.9.2.tgz#3a50f0e7ae6e444d11c61fce12783196454a4efb" + integrity sha512-pL6QtV26W52aCWTG1IuFV3FMPL1m4wbsRG+qijIvgFO/VBsiXJjDPE/uiMdHBAO6YcpV4KvpKtd0v3WFbaxBtg== + +"@rollup/rollup-linux-arm64-musl@4.12.0": + version "4.12.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.12.0.tgz#3882a4e3a564af9e55804beeb67076857b035ab7" + integrity sha512-eTvzUS3hhhlgeAv6bfigekzWZjaEX9xP9HhxB0Dvrdbkk5w/b+1Sxct2ZuDxNJKzsRStSq1EaEkVSEe7A7ipgQ== + +"@rollup/rollup-linux-arm64-musl@4.9.2": + version "4.9.2" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.9.2.tgz#82b5e75484d91c25d4e649d018d9523e72d6dac2" + integrity sha512-On+cc5EpOaTwPSNetHXBuqylDW+765G/oqB9xGmWU3npEhCh8xu0xqHGUA+4xwZLqBbIZNcBlKSIYfkBm6ko7g== + +"@rollup/rollup-linux-riscv64-gnu@4.9.2": + version "4.9.2" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.9.2.tgz#ca96f2d43a553d73aec736e991c07010561bc7a9" + integrity sha512-Wnx/IVMSZ31D/cO9HSsU46FjrPWHqtdF8+0eyZ1zIB5a6hXaZXghUKpRrC4D5DcRTZOjml2oBhXoqfGYyXKipw== + +"@rollup/rollup-linux-x64-gnu@4.9.2": + version "4.9.2" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.9.2.tgz#db1cece244ea46706c0e1a522ec19ca0173abc55" + integrity sha512-ym5x1cj4mUAMBummxxRkI4pG5Vht1QMsJexwGP8547TZ0sox9fCLDHw9KCH9c1FO5d9GopvkaJsBIOkTKxksdw== + +"@rollup/rollup-linux-x64-musl@4.9.2": + version "4.9.2" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.9.2.tgz#c15b26b86827f75977bf59ebd41ce5d788713936" + integrity sha512-m0hYELHGXdYx64D6IDDg/1vOJEaiV8f1G/iO+tejvRCJNSwK4jJ15e38JQy5Q6dGkn1M/9KcyEOwqmlZ2kqaZg== + +"@rollup/rollup-win32-arm64-msvc@4.9.2": + version "4.9.2" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.9.2.tgz#60152948f9fb08e8c50c1555e334ca9f9f1f53aa" + integrity sha512-x1CWburlbN5JjG+juenuNa4KdedBdXLjZMp56nHFSHTOsb/MI2DYiGzLtRGHNMyydPGffGId+VgjOMrcltOksA== + +"@rollup/rollup-win32-ia32-msvc@4.9.2": + version "4.9.2" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.9.2.tgz#657288cff10311f997d8dbd648590441760ae6d9" + integrity sha512-VVzCB5yXR1QlfsH1Xw1zdzQ4Pxuzv+CPr5qpElpKhVxlxD3CRdfubAG9mJROl6/dmj5gVYDDWk8sC+j9BI9/kQ== + +"@rollup/rollup-win32-x64-msvc@4.9.2": + version "4.9.2" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.9.2.tgz#830f3a3fba67f6216a5884368431918029045afe" + integrity sha512-SYRedJi+mweatroB+6TTnJYLts0L0bosg531xnQWtklOI6dezEagx4Q0qDyvRdK+qgdA3YZpjjGuPFtxBmddBA== + "@sentry-internal/feedback@7.85.0": version "7.85.0" resolved "https://registry.npmjs.org/@sentry-internal/feedback/-/feedback-7.85.0.tgz" @@ -2338,7 +2723,7 @@ dependencies: memoizerific "^1.11.3" -"@storybook/blocks@^7.4.5", "@storybook/blocks@7.6.3": +"@storybook/blocks@7.6.3", "@storybook/blocks@^7.4.5": version "7.6.3" resolved "https://registry.npmjs.org/@storybook/blocks/-/blocks-7.6.3.tgz" integrity sha512-EyjyNNCZMcV9UnBSujwduiq+F1VLVX/f16fTTPqqZOHigyfrG5LoEYC6dwOC4yO/xfWY+h3qJ51yiugMxVl0Vg== @@ -2521,7 +2906,7 @@ "@storybook/client-logger" "7.6.3" "@storybook/preview-api" "7.6.3" -"@storybook/core-common@^7.0.0-beta.0 || ^7.0.0-rc.0 || ^7.0.0", "@storybook/core-common@7.6.3": +"@storybook/core-common@7.6.3", "@storybook/core-common@^7.0.0-beta.0 || ^7.0.0-rc.0 || ^7.0.0": version "7.6.3" resolved "https://registry.npmjs.org/@storybook/core-common/-/core-common-7.6.3.tgz" integrity sha512-/ZE4BEyGwBHCQCOo681GyBKF4IqCiwVV/ZJCHTMTHFCPLJT2r+Qwv4tnI7xt1kwflOlbBlG6B6CvAqTjjVw/Ew== @@ -2612,7 +2997,7 @@ "@storybook/csf-tools" "7.6.3" unplugin "^1.3.1" -"@storybook/csf-tools@^7.0.0-beta.0 || ^7.0.0-rc.0 || ^7.0.0", "@storybook/csf-tools@7.6.3": +"@storybook/csf-tools@7.6.3", "@storybook/csf-tools@^7.0.0-beta.0 || ^7.0.0-rc.0 || ^7.0.0": version "7.6.3" resolved "https://registry.npmjs.org/@storybook/csf-tools/-/csf-tools-7.6.3.tgz" integrity sha512-Zi3pg2pg88/mvBKewkfWhFUR1J4uYpHI5fSjOE+J/FeZObX/DIE7r+wJxZ0UBGyrk0Wy7Jajlb2uSP56Y0i19w== @@ -2722,7 +3107,7 @@ resolved "https://registry.npmjs.org/@storybook/postinstall/-/postinstall-7.6.3.tgz" integrity sha512-WpgdpJpY6rionluxjFZLbKiSDjvQJ5cPgufjvBRuXTsnVOsH3JNRWnPdkQkJLT9uTUMoNcyBMxbjYkK3vU6wSg== -"@storybook/preview-api@^7.0.0-beta.0 || ^7.0.0-rc.0 || ^7.0.0", "@storybook/preview-api@7.6.3": +"@storybook/preview-api@7.6.3", "@storybook/preview-api@^7.0.0-beta.0 || ^7.0.0-rc.0 || ^7.0.0": version "7.6.3" resolved "https://registry.npmjs.org/@storybook/preview-api/-/preview-api-7.6.3.tgz" integrity sha512-uPaK7yLE1P++F+IOb/1j9pgdCwfMYZrUPHogF/Mf9r4cfEjDCcIeKgGMcsbU1KnkzNQQGPh8JRzRr/iYnLjswg== @@ -2765,7 +3150,7 @@ magic-string "^0.30.0" react-docgen "^7.0.0" -"@storybook/react@^7.4.5", "@storybook/react@7.6.3": +"@storybook/react@7.6.3", "@storybook/react@^7.4.5": version "7.6.3" resolved "https://registry.npmjs.org/@storybook/react/-/react-7.6.3.tgz" integrity sha512-W+530cC0BAU+yBc7NzSXYWR3e8Lo5qMsmFJjWYK7zGW/YZGhSG3mjhF9pDzNM+cMtHvUS6qf5PJPQM8jePpPhg== @@ -2801,7 +3186,7 @@ memoizerific "^1.11.3" qs "^6.10.0" -"@storybook/telemetry@^7.1.0", "@storybook/telemetry@7.6.3": +"@storybook/telemetry@7.6.3", "@storybook/telemetry@^7.1.0": version "7.6.3" resolved "https://registry.npmjs.org/@storybook/telemetry/-/telemetry-7.6.3.tgz" integrity sha512-NDCZWhVIUI3M6Lq4M/HPOvZqDXqANDNbI3kyHr4pFGoVaCUXuDPokL9wR+CZcMvATkJ1gHrfLPBdcRq6Biw3Iw== @@ -2883,7 +3268,47 @@ resolved "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.3.100.tgz" integrity sha512-XVWFsKe6ei+SsDbwmsuRkYck1SXRpO60Hioa4hoLwR8fxbA9eVp6enZtMxzVVMBi8ej5seZ4HZQeAWepbukiBw== -"@swc/core@*", "@swc/core@^1.3.18": +"@swc/core-darwin-x64@1.3.100": + version "1.3.100" + resolved "https://registry.yarnpkg.com/@swc/core-darwin-x64/-/core-darwin-x64-1.3.100.tgz#d84f5c0bb4603c252884d011a698ed7c634b1505" + integrity sha512-KF/MXrnH1nakm1wbt4XV8FS7kvqD9TGmVxeJ0U4bbvxXMvzeYUurzg3AJUTXYmXDhH/VXOYJE5N5RkwZZPs5iA== + +"@swc/core-linux-arm64-gnu@1.3.100": + version "1.3.100" + resolved "https://registry.yarnpkg.com/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.3.100.tgz#1ed4b92b373882d8f338c4e0a0aa64cdaa6106f1" + integrity sha512-p8hikNnAEJrw5vHCtKiFT4hdlQxk1V7vqPmvUDgL/qe2menQDK/i12tbz7/3BEQ4UqUPnvwpmVn2d19RdEMNxw== + +"@swc/core-linux-arm64-musl@1.3.100": + version "1.3.100" + resolved "https://registry.yarnpkg.com/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.3.100.tgz#9db560f7459e42e65ec02670d6a8316e7c850cfc" + integrity sha512-BWx/0EeY89WC4q3AaIaBSGfQxkYxIlS3mX19dwy2FWJs/O+fMvF9oLk/CyJPOZzbp+1DjGeeoGFuDYpiNO91JA== + +"@swc/core-linux-x64-gnu@1.3.100": + version "1.3.100" + resolved "https://registry.yarnpkg.com/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.3.100.tgz#228826ea48879bf1e73683fbef4373e3e762e424" + integrity sha512-XUdGu3dxAkjsahLYnm8WijPfKebo+jHgHphDxaW0ovI6sTdmEGFDew7QzKZRlbYL2jRkUuuKuDGvD6lO5frmhA== + +"@swc/core-linux-x64-musl@1.3.100": + version "1.3.100" + resolved "https://registry.yarnpkg.com/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.3.100.tgz#09a234dbbf625d071ecb663680e997a62d230d49" + integrity sha512-PhoXKf+f0OaNW/GCuXjJ0/KfK9EJX7z2gko+7nVnEA0p3aaPtbP6cq1Ubbl6CMoPL+Ci3gZ7nYumDqXNc3CtLQ== + +"@swc/core-win32-arm64-msvc@1.3.100": + version "1.3.100" + resolved "https://registry.yarnpkg.com/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.3.100.tgz#add1c82884c10a9054ed6a48f884097aa85c6d2b" + integrity sha512-PwLADZN6F9cXn4Jw52FeP/MCLVHm8vwouZZSOoOScDtihjY495SSjdPnlosMaRSR4wJQssGwiD/4MbpgQPqbAw== + +"@swc/core-win32-ia32-msvc@1.3.100": + version "1.3.100" + resolved "https://registry.yarnpkg.com/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.3.100.tgz#e0b6c5ae7f3250adeeb88dae83558d3f45148c56" + integrity sha512-0f6nicKSLlDKlyPRl2JEmkpBV4aeDfRQg6n8mPqgL7bliZIcDahG0ej+HxgNjZfS3e0yjDxsNRa6sAqWU2Z60A== + +"@swc/core-win32-x64-msvc@1.3.100": + version "1.3.100" + resolved "https://registry.yarnpkg.com/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.3.100.tgz#34721dff151d7dcf165675f18aeed0a12264d88c" + integrity sha512-b7J0rPoMkRTa3XyUGt8PwCaIBuYWsL2DqbirrQKRESzgCvif5iNpqaM6kjIjI/5y5q1Ycv564CB51YDpiS8EtQ== + +"@swc/core@^1.3.18": version "1.3.100" resolved "https://registry.npmjs.org/@swc/core/-/core-1.3.100.tgz" integrity sha512-7dKgTyxJjlrMwFZYb1auj3Xq0D8ZBe+5oeIgfMlRU05doXZypYJe0LAk0yjj3WdbwYzpF+T1PLxwTWizI0pckw== @@ -2919,7 +3344,7 @@ resolved "https://registry.npmjs.org/@swc/types/-/types-0.1.5.tgz" integrity sha512-myfUej5naTBWnqOCc/MdVOLVjXUXtIA+NpDrDBKJtLLg2shUjBu3cZmB/85RyitKc55+lUUyl7oRfLOvkr2hsw== -"@testing-library/dom@^9.0.0", "@testing-library/dom@>=7.21.4": +"@testing-library/dom@^9.0.0": version "9.3.3" resolved "https://registry.npmjs.org/@testing-library/dom/-/dom-9.3.3.tgz" integrity sha512-fB0R+fa3AUqbLHWyxXa2kGVtf1Fe1ZZFr0Zp6AIbIAzXb2mKbEXl+PCQNUOaq5lbTab5tfctfXRNsWXxa2f7Aw== @@ -3149,7 +3574,7 @@ dependencies: "@types/istanbul-lib-report" "*" -"@types/jest@>= 28", "@types/jest@28.1.3": +"@types/jest@28.1.3": version "28.1.3" resolved "https://registry.npmjs.org/@types/jest/-/jest-28.1.3.tgz" integrity sha512-Tsbjk8Y2hkBaY/gJsataeb4q9Mubw9EOz7+4RjPkzD5KjTvHHs7cpws22InaoXxAVAhF5HfFbzJjo6oKWqSZLw== @@ -3210,7 +3635,7 @@ "@types/node" "*" form-data "^4.0.0" -"@types/node@*", "@types/node@^18.0.0 || >=20.0.0", "@types/node@^20.4.8", "@types/node@>= 14": +"@types/node@*", "@types/node@^20.4.8": version "20.10.3" resolved "https://registry.npmjs.org/@types/node/-/node-20.10.3.tgz" integrity sha512-XJavIpZqiXID5Yxnxv3RUDKTN5b81ddNC3ecsA0SoFXz/QU8OGBwZGMomiq0zw+uuqbL/krztv/DINAQ/EV4gg== @@ -3254,13 +3679,6 @@ resolved "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz" integrity sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ== -"@types/react-dom@*", "@types/react-dom@^18.0.11": - version "18.2.17" - resolved "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.2.17.tgz" - integrity sha512-rvrT/M7Df5eykWFxn6MYt5Pem/Dbyc1N8Y0S9Mrkw2WFCRiqUgw9P7ul2NpwsXCSM1DVdENzdG9J5SreqfAIWg== - dependencies: - "@types/react" "*" - "@types/react-dom@^18.0.0": version "18.2.18" resolved "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.2.18.tgz" @@ -3268,6 +3686,13 @@ dependencies: "@types/react" "*" +"@types/react-dom@^18.0.11": + version "18.2.17" + resolved "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.2.17.tgz" + integrity sha512-rvrT/M7Df5eykWFxn6MYt5Pem/Dbyc1N8Y0S9Mrkw2WFCRiqUgw9P7ul2NpwsXCSM1DVdENzdG9J5SreqfAIWg== + dependencies: + "@types/react" "*" + "@types/react-gtm-module@^2.0.2": version "2.0.3" resolved "https://registry.npmjs.org/@types/react-gtm-module/-/react-gtm-module-2.0.3.tgz" @@ -3280,7 +3705,7 @@ dependencies: "@types/react" "*" -"@types/react@*", "@types/react@^16.8.0 || ^17.0.0 || ^18.0.0", "@types/react@^16.9.0 || ^17.0.0 || ^18.0.0", "@types/react@^17.0.0 || ^18.0.0", "@types/react@^18.2.12", "@types/react@>=16": +"@types/react@*", "@types/react@>=16", "@types/react@^18.2.12": version "18.2.42" resolved "https://registry.npmjs.org/@types/react/-/react-18.2.42.tgz" integrity sha512-c1zEr96MjakLYus/wPnuWDo1/zErfdU9rNsIGmE+NV71nx88FG9Ttgo5dqorXTu/LImX2f63WBP986gJkMPNbA== @@ -3362,7 +3787,7 @@ dependencies: "@types/yargs-parser" "*" -"@typescript-eslint/eslint-plugin@^5.0.0 || ^6.0.0 || ^7.0.0", "@typescript-eslint/eslint-plugin@^7.3.1": +"@typescript-eslint/eslint-plugin@^7.3.1": version "7.3.1" resolved "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.3.1.tgz" integrity sha512-STEDMVQGww5lhCuNXVSQfbfuNII5E08QWkvAw5Qwf+bj2WT+JkG1uc+5/vXA3AOYMDHVOSpL+9rcbEUiHIm2dw== @@ -3379,7 +3804,7 @@ semver "^7.5.4" ts-api-utils "^1.0.1" -"@typescript-eslint/parser@^7.0.0", "@typescript-eslint/parser@^7.3.1": +"@typescript-eslint/parser@^7.3.1": version "7.3.1" resolved "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.3.1.tgz" integrity sha512-Rq49+pq7viTRCH48XAbTA+wdLRrB/3sRq4Lpk0oGDm0VmnjBrAOVXH/Laalmwsv2VpekiEfVFwJYVk6/e8uvQw== @@ -3453,6 +3878,19 @@ semver "^7.5.4" ts-api-utils "^1.0.1" +"@typescript-eslint/utils@7.3.1": + version "7.3.1" + resolved "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.3.1.tgz" + integrity sha512-jIERm/6bYQ9HkynYlNZvXpzmXWZGhMbrOvq3jJzOSOlKXsVjrrolzWBjDW6/TvT5Q3WqaN4EkmcfdQwi9tDjBQ== + dependencies: + "@eslint-community/eslint-utils" "^4.4.0" + "@types/json-schema" "^7.0.12" + "@types/semver" "^7.5.0" + "@typescript-eslint/scope-manager" "7.3.1" + "@typescript-eslint/types" "7.3.1" + "@typescript-eslint/typescript-estree" "7.3.1" + semver "^7.5.4" + "@typescript-eslint/utils@^5.10.0", "@typescript-eslint/utils@^5.45.0": version "5.62.0" resolved "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.62.0.tgz" @@ -3467,19 +3905,6 @@ eslint-scope "^5.1.1" semver "^7.3.7" -"@typescript-eslint/utils@7.3.1": - version "7.3.1" - resolved "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.3.1.tgz" - integrity sha512-jIERm/6bYQ9HkynYlNZvXpzmXWZGhMbrOvq3jJzOSOlKXsVjrrolzWBjDW6/TvT5Q3WqaN4EkmcfdQwi9tDjBQ== - dependencies: - "@eslint-community/eslint-utils" "^4.4.0" - "@types/json-schema" "^7.0.12" - "@types/semver" "^7.5.0" - "@typescript-eslint/scope-manager" "7.3.1" - "@typescript-eslint/types" "7.3.1" - "@typescript-eslint/typescript-estree" "7.3.1" - semver "^7.5.4" - "@typescript-eslint/visitor-keys@5.62.0": version "5.62.0" resolved "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.62.0.tgz" @@ -3557,7 +3982,7 @@ dependencies: tinyspy "^2.2.0" -"@vitest/ui@^1.0.0", "@vitest/ui@^1.1.0": +"@vitest/ui@^1.1.0": version "1.1.0" resolved "https://registry.npmjs.org/@vitest/ui/-/ui-1.1.0.tgz" integrity sha512-7yU1QRFBplz0xJqcgt+agcbrNFdBmLo8UUppdKkFmYx+Ih0+yMYQOyr7kOB+YoggJY/p5ZzXxdbiOz7NBX2y+w== @@ -3604,7 +4029,7 @@ "@yarnpkg/libzip" "^2.3.0" tslib "^1.13.0" -"@yarnpkg/libzip@^2.3.0", "@yarnpkg/libzip@2.3.0": +"@yarnpkg/libzip@2.3.0", "@yarnpkg/libzip@^2.3.0": version "2.3.0" resolved "https://registry.npmjs.org/@yarnpkg/libzip/-/libzip-2.3.0.tgz" integrity sha512-6xm38yGVIa6mKm/DUCF2zFFJhERh/QWp1ufm4cNUvxsONBmfPg8uZ9pZBdOmF6qFGr/HlT6ABBkCSx/dlEtvWg== @@ -3647,7 +4072,7 @@ acorn-walk@^8.3.2: resolved "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.2.tgz" integrity sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A== -"acorn@^6.0.0 || ^7.0.0 || ^8.0.0", acorn@^7.4.1: +acorn@^7.4.1: version "7.4.1" resolved "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz" integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A== @@ -3657,12 +4082,7 @@ acorn@^8.10.0: resolved "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz" integrity sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg== -acorn@^8.11.2: - version "8.11.2" - resolved "https://registry.npmjs.org/acorn/-/acorn-8.11.2.tgz" - integrity sha512-nc0Axzp/0FILLEVsm4fNwLCwMttvhEI263QtVPQcbpfZZ3ts0hLsZGOpE6czNlid7CJ9MlyH8reXkpsf3YUY4w== - -acorn@^8.9.0: +acorn@^8.11.2, acorn@^8.9.0: version "8.11.2" resolved "https://registry.npmjs.org/acorn/-/acorn-8.11.2.tgz" integrity sha512-nc0Axzp/0FILLEVsm4fNwLCwMttvhEI263QtVPQcbpfZZ3ts0hLsZGOpE6czNlid7CJ9MlyH8reXkpsf3YUY4w== @@ -3672,6 +4092,11 @@ address@^1.0.1: resolved "https://registry.npmjs.org/address/-/address-1.2.2.tgz" integrity sha512-4B/qKCfeE/ODUaAUpSwfzazo5x29WD4r3vXiWsB7I2mSDAihwEqKO+g8GELZUQSSAo5e1XTYh3ZVfLyxBc12nA== +agent-base@5: + version "5.1.1" + resolved "https://registry.npmjs.org/agent-base/-/agent-base-5.1.1.tgz" + integrity sha512-TMeqbNl2fMW0nMjTEPOwe3J/PRFP4vqeoNuQMG0HlMrtm5QxKqdvAkZ1pRBQ/ulIyDD5Yq0nJ7YbdD8ey0TO3g== + agent-base@^7.0.2, agent-base@^7.1.0: version "7.1.0" resolved "https://registry.npmjs.org/agent-base/-/agent-base-7.1.0.tgz" @@ -3679,11 +4104,6 @@ agent-base@^7.0.2, agent-base@^7.1.0: dependencies: debug "^4.3.4" -agent-base@5: - version "5.1.1" - resolved "https://registry.npmjs.org/agent-base/-/agent-base-5.1.1.tgz" - integrity sha512-TMeqbNl2fMW0nMjTEPOwe3J/PRFP4vqeoNuQMG0HlMrtm5QxKqdvAkZ1pRBQ/ulIyDD5Yq0nJ7YbdD8ey0TO3g== - aggregate-error@^3.0.0: version "3.1.0" resolved "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz" @@ -3697,7 +4117,7 @@ ajv-keywords@^3.5.2: resolved "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz" integrity sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ== -ajv@^6.12.4, ajv@^6.9.1: +ajv@^6.12.4: version "6.12.6" resolved "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz" integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== @@ -3799,13 +4219,6 @@ aria-hidden@^1.1.1: dependencies: tslib "^2.0.0" -aria-query@^5.0.0, aria-query@^5.3.0: - version "5.3.0" - resolved "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz" - integrity sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A== - dependencies: - dequal "^2.0.3" - aria-query@5.1.3: version "5.1.3" resolved "https://registry.npmjs.org/aria-query/-/aria-query-5.1.3.tgz" @@ -3813,6 +4226,13 @@ aria-query@5.1.3: dependencies: deep-equal "^2.0.5" +aria-query@^5.0.0, aria-query@^5.3.0: + version "5.3.0" + resolved "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz" + integrity sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A== + dependencies: + dequal "^2.0.3" + array-buffer-byte-length@^1.0.0, array-buffer-byte-length@^1.0.1: version "1.0.1" resolved "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.1.tgz" @@ -4224,7 +4644,7 @@ browserify-zlib@^0.1.4: dependencies: pako "~0.2.0" -browserslist@^4.21.9, browserslist@^4.22.1, "browserslist@>= 4.21.0": +browserslist@^4.21.9, browserslist@^4.22.1: version "4.22.2" resolved "https://registry.npmjs.org/browserslist/-/browserslist-4.22.2.tgz" integrity sha512-0UgcrvQmBDvZHFGdYUehrCNIazki7/lUP3kkoi/r3YB2amZbFM9J43ZRkJTXBUZK4gmx56+Sqk9+Vs9mwZx9+A== @@ -4520,16 +4940,16 @@ color-convert@^2.0.1: dependencies: color-name "~1.1.4" -color-name@^1.0.0, color-name@~1.1.4: - version "1.1.4" - resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz" - integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== - color-name@1.1.3: version "1.1.3" resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz" integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw== +color-name@^1.0.0, color-name@~1.1.4: + version "1.1.4" + resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz" + integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== + color-string@^1.6.0: version "1.9.1" resolved "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz" @@ -4635,12 +5055,7 @@ content-type@~1.0.4: resolved "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz" integrity sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA== -convert-source-map@^1.5.0: - version "1.9.0" - resolved "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz" - integrity sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A== - -convert-source-map@^1.7.0: +convert-source-map@^1.5.0, convert-source-map@^1.7.0: version "1.9.0" resolved "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz" integrity sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A== @@ -4787,33 +5202,26 @@ date-fns@^2.30.0: dependencies: "@babel/runtime" "^7.21.0" -debug@^2.6.9: +debug@2.6.9, debug@^2.6.9: version "2.6.9" resolved "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz" integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== dependencies: ms "2.0.0" -debug@^3.2.7: - version "3.2.7" - resolved "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz" - integrity sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ== - dependencies: - ms "^2.1.1" - -debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.4, debug@4: +debug@4, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.4: version "4.3.4" resolved "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz" integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== dependencies: ms "2.1.2" -debug@2.6.9: - version "2.6.9" - resolved "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz" - integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== +debug@^3.2.7: + version "3.2.7" + resolved "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz" + integrity sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ== dependencies: - ms "2.0.0" + ms "^2.1.1" decamelize@^1.2.0: version "1.2.0" @@ -5049,7 +5457,7 @@ dom-serializer@0: domelementtype "^2.0.1" entities "^2.0.0" -domelementtype@^1.3.1, domelementtype@1: +domelementtype@1, domelementtype@^1.3.1: version "1.3.1" resolved "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz" integrity sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w== @@ -5328,35 +5736,7 @@ esbuild-register@^3.5.0: dependencies: debug "^4.3.4" -esbuild@^0.18.0, esbuild@>=0.10.0, "esbuild@>=0.12 <1": - version "0.18.20" - resolved "https://registry.npmjs.org/esbuild/-/esbuild-0.18.20.tgz" - integrity sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA== - optionalDependencies: - "@esbuild/android-arm" "0.18.20" - "@esbuild/android-arm64" "0.18.20" - "@esbuild/android-x64" "0.18.20" - "@esbuild/darwin-arm64" "0.18.20" - "@esbuild/darwin-x64" "0.18.20" - "@esbuild/freebsd-arm64" "0.18.20" - "@esbuild/freebsd-x64" "0.18.20" - "@esbuild/linux-arm" "0.18.20" - "@esbuild/linux-arm64" "0.18.20" - "@esbuild/linux-ia32" "0.18.20" - "@esbuild/linux-loong64" "0.18.20" - "@esbuild/linux-mips64el" "0.18.20" - "@esbuild/linux-ppc64" "0.18.20" - "@esbuild/linux-riscv64" "0.18.20" - "@esbuild/linux-s390x" "0.18.20" - "@esbuild/linux-x64" "0.18.20" - "@esbuild/netbsd-x64" "0.18.20" - "@esbuild/openbsd-x64" "0.18.20" - "@esbuild/sunos-x64" "0.18.20" - "@esbuild/win32-arm64" "0.18.20" - "@esbuild/win32-ia32" "0.18.20" - "@esbuild/win32-x64" "0.18.20" - -esbuild@^0.18.10: +esbuild@^0.18.0, esbuild@^0.18.10: version "0.18.20" resolved "https://registry.npmjs.org/esbuild/-/esbuild-0.18.20.tgz" integrity sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA== @@ -5512,7 +5892,7 @@ eslint-module-utils@^2.8.0: dependencies: debug "^3.2.7" -eslint-plugin-import@^2.25.2, eslint-plugin-import@^2.25.3, eslint-plugin-import@^2.29.1: +eslint-plugin-import@^2.29.1: version "2.29.1" resolved "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.29.1.tgz" integrity sha512-BbPC0cuExzhiMo4Ff1BTVwHpjjv28C5R+btTOGaCRC7UEz801up0JadwkeSk5Ued6TG34uaczuVuH6qyy5YUxw== @@ -5542,7 +5922,7 @@ eslint-plugin-jest@^27.9.0: dependencies: "@typescript-eslint/utils" "^5.10.0" -eslint-plugin-jsx-a11y@^6.5.1, eslint-plugin-jsx-a11y@^6.8.0: +eslint-plugin-jsx-a11y@^6.8.0: version "6.8.0" resolved "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.8.0.tgz" integrity sha512-Hdh937BS3KdwwbBaKd5+PLCOmYY6U4f2h9Z2ktwtNKvIdIEu137rjYbcb9ApSbVJfWxANNuiKTD/9tOKjK9qOA== @@ -5564,7 +5944,7 @@ eslint-plugin-jsx-a11y@^6.5.1, eslint-plugin-jsx-a11y@^6.8.0: object.entries "^1.1.7" object.fromentries "^2.0.7" -eslint-plugin-react-hooks@^4.3.0, eslint-plugin-react-hooks@^4.6.0: +eslint-plugin-react-hooks@^4.6.0: version "4.6.0" resolved "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.0.tgz" integrity sha512-oFc7Itz9Qxh2x4gNHStv3BqJq54ExXmfC+a1NjAta66IAN87Wu0R/QArgIS9qKzX3dXKPI9H5crl9QchNMY9+g== @@ -5574,7 +5954,7 @@ eslint-plugin-react-refresh@^0.3.4: resolved "https://registry.npmjs.org/eslint-plugin-react-refresh/-/eslint-plugin-react-refresh-0.3.5.tgz" integrity sha512-61qNIsc7fo9Pp/mju0J83kzvLm0Bsayu7OQSLEoJxLDCBjIIyb87bkzufoOvdDxLkSlMfkF7UxomC4+eztUBSA== -eslint-plugin-react@^7.28.0, eslint-plugin-react@^7.34.1: +eslint-plugin-react@^7.34.1: version "7.34.1" resolved "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.34.1.tgz" integrity sha512-N97CxlouPT1AHt8Jn0mhhN2RrADlUAsk1/atcT2KyA/l9Q/E6ll7OIGwNumFmWfZ9skV3XXccYS19h80rHtgkw== @@ -5629,7 +6009,7 @@ eslint-visitor-keys@^3.3.0, eslint-visitor-keys@^3.4.1, eslint-visitor-keys@^3.4 resolved "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz" integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag== -"eslint@^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8", "eslint@^3 || ^4 || ^5 || ^6 || ^7 || ^8", "eslint@^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0", "eslint@^6.0.0 || ^7.0.0 || ^8.0.0", "eslint@^6.0.0 || ^7.0.0 || >=8.0.0", "eslint@^7.0.0 || ^8.0.0", "eslint@^7.32.0 || ^8.2.0", eslint@^8.38.0, eslint@^8.56.0, eslint@>=6, eslint@>=7: +eslint@^8.38.0: version "8.57.0" resolved "https://registry.npmjs.org/eslint/-/eslint-8.57.0.tgz" integrity sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ== @@ -6120,6 +6500,15 @@ fs-exists-sync@^0.1.0: resolved "https://registry.npmjs.org/fs-exists-sync/-/fs-exists-sync-0.1.0.tgz" integrity sha512-cR/vflFyPZtrN6b38ZyWxpWdhlXrzZEBawlpBQMq7033xVY7/kg0GDMBK5jg8lDYQckdJ5x/YC88lM3C7VMsLg== +fs-extra@11.1.1: + version "11.1.1" + resolved "https://registry.npmjs.org/fs-extra/-/fs-extra-11.1.1.tgz" + integrity sha512-MGIE4HOvQCeUCzmlHs0vXpih4ysz4wg9qiSAu6cd42lVwPbTM1TjV7RusoyQqMmk/95gdQZX72u+YW+c3eEpFQ== + dependencies: + graceful-fs "^4.2.0" + jsonfile "^6.0.1" + universalify "^2.0.0" + fs-extra@^11.1.0: version "11.2.0" resolved "https://registry.npmjs.org/fs-extra/-/fs-extra-11.2.0.tgz" @@ -6139,15 +6528,6 @@ fs-extra@^9.0.0: jsonfile "^6.0.1" universalify "^2.0.0" -fs-extra@11.1.1: - version "11.1.1" - resolved "https://registry.npmjs.org/fs-extra/-/fs-extra-11.1.1.tgz" - integrity sha512-MGIE4HOvQCeUCzmlHs0vXpih4ysz4wg9qiSAu6cd42lVwPbTM1TjV7RusoyQqMmk/95gdQZX72u+YW+c3eEpFQ== - dependencies: - graceful-fs "^4.2.0" - jsonfile "^6.0.1" - universalify "^2.0.0" - fs-minipass@^2.0.0: version "2.1.0" resolved "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz" @@ -6160,16 +6540,16 @@ fs.realpath@^1.0.0: resolved "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz" integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== -fsevents@^2.3.2, fsevents@~2.3.2, fsevents@~2.3.3: - version "2.3.3" - resolved "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz" - integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== - fsevents@2.3.2: version "2.3.2" resolved "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz" integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== +fsevents@^2.3.2, fsevents@~2.3.2, fsevents@~2.3.3: + version "2.3.3" + resolved "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz" + integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== + function-bind@^1.1.2: version "1.1.2" resolved "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz" @@ -6299,18 +6679,7 @@ glob-to-regexp@^0.4.1: resolved "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz" integrity sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw== -glob@^10.0.0: - version "10.3.10" - resolved "https://registry.npmjs.org/glob/-/glob-10.3.10.tgz" - integrity sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g== - dependencies: - foreground-child "^3.1.0" - jackspeak "^2.3.5" - minimatch "^9.0.1" - minipass "^5.0.0 || ^6.0.2 || ^7.0.0" - path-scurry "^1.10.1" - -glob@^10.2.2: +glob@^10.0.0, glob@^10.2.2: version "10.3.10" resolved "https://registry.npmjs.org/glob/-/glob-10.3.10.tgz" integrity sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g== @@ -6577,7 +6946,7 @@ human-signals@^5.0.0: resolved "https://registry.npmjs.org/human-signals/-/human-signals-5.0.0.tgz" integrity sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ== -i18next@^23.7.19, "i18next@>= 23.2.3": +i18next@^23.7.19: version "23.7.19" resolved "https://registry.npmjs.org/i18next/-/i18next-23.7.19.tgz" integrity sha512-1aP+YSJl+nLxr42ZJtNhpWpNWYsc6nCbVCf2x4uizIX1BYfcigiRMlb3vOkE1p3+qrI+aD6h5G2Fg+2d2oMIOQ== @@ -6642,7 +7011,7 @@ inflight@^1.0.4: once "^1.3.0" wrappy "1" -inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.3, inherits@2, inherits@2.0.4: +inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.3: version "2.0.4" resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== @@ -6860,6 +7229,11 @@ is-path-inside@^3.0.2, is-path-inside@^3.0.3: resolved "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz" integrity sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ== +is-plain-object@5.0.0: + version "5.0.0" + resolved "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz" + integrity sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q== + is-plain-object@^2.0.4: version "2.0.4" resolved "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz" @@ -6867,11 +7241,6 @@ is-plain-object@^2.0.4: dependencies: isobject "^3.0.1" -is-plain-object@5.0.0: - version "5.0.0" - resolved "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz" - integrity sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q== - is-potential-custom-element-name@^1.0.1: version "1.0.1" resolved "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz" @@ -7017,18 +7386,7 @@ istanbul-lib-instrument@^4.0.0, istanbul-lib-instrument@^4.0.3: istanbul-lib-coverage "^3.0.0" semver "^6.3.0" -istanbul-lib-instrument@^5.0.4: - version "5.2.1" - resolved "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz" - integrity sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg== - dependencies: - "@babel/core" "^7.12.3" - "@babel/parser" "^7.14.7" - "@istanbuljs/schema" "^0.1.2" - istanbul-lib-coverage "^3.2.0" - semver "^6.3.0" - -istanbul-lib-instrument@^5.1.0: +istanbul-lib-instrument@^5.0.4, istanbul-lib-instrument@^5.1.0: version "5.2.1" resolved "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz" integrity sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg== @@ -7039,18 +7397,7 @@ istanbul-lib-instrument@^5.1.0: istanbul-lib-coverage "^3.2.0" semver "^6.3.0" -istanbul-lib-instrument@^6.0.0: - version "6.0.1" - resolved "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.1.tgz" - integrity sha512-EAMEJBsYuyyztxMxW3g7ugGPkrZsV57v0Hmv3mm1uQsmB+QnZuepg731CRaIgeUVSdmsTngOkSnauNF8p7FIhA== - dependencies: - "@babel/core" "^7.12.3" - "@babel/parser" "^7.14.7" - "@istanbuljs/schema" "^0.1.2" - istanbul-lib-coverage "^3.2.0" - semver "^7.5.4" - -istanbul-lib-instrument@^6.0.1: +istanbul-lib-instrument@^6.0.0, istanbul-lib-instrument@^6.0.1: version "6.0.1" resolved "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.1.tgz" integrity sha512-EAMEJBsYuyyztxMxW3g7ugGPkrZsV57v0Hmv3mm1uQsmB+QnZuepg731CRaIgeUVSdmsTngOkSnauNF8p7FIhA== @@ -7138,7 +7485,7 @@ jest-changed-files@^29.7.0: jest-util "^29.7.0" p-limit "^3.1.0" -jest-circus@^29.3.1, jest-circus@^29.6.4, jest-circus@^29.7.0: +jest-circus@^29.6.4, jest-circus@^29.7.0: version "29.7.0" resolved "https://registry.npmjs.org/jest-circus/-/jest-circus-29.7.0.tgz" integrity sha512-3E1nCMgipcTkCocFwM90XXQab9bS+GMsjdpmPrlelaxwD93Ad8iVEjX/vvHPdLPnFf+L40u+5+iutRdA1N9myw== @@ -7247,7 +7594,7 @@ jest-each@^29.7.0: jest-util "^29.7.0" pretty-format "^29.7.0" -jest-environment-node@^29.3.1, jest-environment-node@^29.6.4, jest-environment-node@^29.7.0: +jest-environment-node@^29.6.4, jest-environment-node@^29.7.0: version "29.7.0" resolved "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.7.0.tgz" integrity sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw== @@ -7341,15 +7688,7 @@ jest-message-util@^29.7.0: slash "^3.0.0" stack-utils "^2.0.3" -jest-mock@^27.0.6: - version "27.5.1" - resolved "https://registry.npmjs.org/jest-mock/-/jest-mock-27.5.1.tgz" - integrity sha512-K4jKbY1d4ENhbrG2zuPWaQBvDly+iZ2yAW+T1fATN78hc0sInwn7wZB8XtlNnvHug5RMwV897Xm4LqmPM4e2Og== - dependencies: - "@jest/types" "^27.5.1" - "@types/node" "*" - -jest-mock@^27.3.0: +jest-mock@^27.0.6, jest-mock@^27.3.0: version "27.5.1" resolved "https://registry.npmjs.org/jest-mock/-/jest-mock-27.5.1.tgz" integrity sha512-K4jKbY1d4ENhbrG2zuPWaQBvDly+iZ2yAW+T1fATN78hc0sInwn7wZB8XtlNnvHug5RMwV897Xm4LqmPM4e2Og== @@ -7412,7 +7751,7 @@ jest-resolve-dependencies@^29.7.0: jest-regex-util "^29.6.3" jest-snapshot "^29.7.0" -jest-resolve@*, jest-resolve@^29.7.0: +jest-resolve@^29.7.0: version "29.7.0" resolved "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.7.0.tgz" integrity sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA== @@ -7427,7 +7766,7 @@ jest-resolve@*, jest-resolve@^29.7.0: resolve.exports "^2.0.0" slash "^3.0.0" -jest-runner@^29.3.1, jest-runner@^29.6.4, jest-runner@^29.7.0: +jest-runner@^29.6.4, jest-runner@^29.7.0: version "29.7.0" resolved "https://registry.npmjs.org/jest-runner/-/jest-runner-29.7.0.tgz" integrity sha512-fsc4N6cPCAahybGBfTRcq5wFR6fpLznMg47sY5aDpsoejOcVYFb07AHuSnR0liMcPTgBsA3ZJL6kFOjPdoNipQ== @@ -7576,7 +7915,7 @@ jest-worker@^29.7.0: merge-stream "^2.0.0" supports-color "^8.0.0" -jest@*, "jest@^27.0.0 || ^28.0.0 || ^29.0.0", jest@^29.3.1, jest@^29.6.4, "jest@>= 28": +jest@^29.6.4: version "29.7.0" resolved "https://registry.npmjs.org/jest/-/jest-29.7.0.tgz" integrity sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw== @@ -7648,7 +7987,7 @@ jscodeshift@^0.15.1: temp "^0.8.4" write-file-atomic "^2.3.0" -jsdom@*, jsdom@^23.0.1: +jsdom@^23.0.1: version "23.0.1" resolved "https://registry.npmjs.org/jsdom/-/jsdom-23.0.1.tgz" integrity sha512-2i27vgvlUsGEBO9+/kJQRbtqtm+191b5zAZrU/UezVmnC2dlDAFLgDYJvAEi94T4kjsRKkezEtLQTgsNEsW2lQ== @@ -7803,7 +8142,7 @@ ky-universal@^0.11.0: abort-controller "^3.0.0" node-fetch "^3.2.10" -ky@^0.33.3, ky@>=0.31.4: +ky@^0.33.3: version "0.33.3" resolved "https://registry.npmjs.org/ky/-/ky-0.33.3.tgz" integrity sha512-CasD9OCEQSFIam2U8efFK81Yeg8vNMTBUqtMOHlrcWQHqUX3HeCl9Dr31u4toV7emlH8Mymk5+9p0lL6mKb/Xw== @@ -8082,7 +8421,7 @@ microseconds@0.2.0: resolved "https://registry.npmjs.org/microseconds/-/microseconds-0.2.0.tgz" integrity sha512-n7DHHMjR1avBbSpsTBj6fmMGh2AGrifVV4e+WYc3Q9lO+xnSZ3NyhcBND3vzzatt05LFhoKFRxrIyklmLlUtyA== -"mime-db@>= 1.43.0 < 2", mime-db@1.52.0: +mime-db@1.52.0, "mime-db@>= 1.43.0 < 2": version "1.52.0" resolved "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz" integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== @@ -8094,16 +8433,16 @@ mime-types@^2.1.12, mime-types@^2.1.25, mime-types@~2.1.24, mime-types@~2.1.34: dependencies: mime-db "1.52.0" -mime@^2.0.3: - version "2.6.0" - resolved "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz" - integrity sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg== - mime@1.6.0: version "1.6.0" resolved "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz" integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== +mime@^2.0.3: + version "2.6.0" + resolved "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz" + integrity sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg== + mimic-fn@^2.1.0: version "2.1.0" resolved "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz" @@ -8119,7 +8458,7 @@ min-indent@^1.0.0, min-indent@^1.0.1: resolved "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz" integrity sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg== -minimatch@*: +minimatch@*, minimatch@9.0.3, minimatch@^9.0.1: version "9.0.3" resolved "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz" integrity sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg== @@ -8140,20 +8479,6 @@ minimatch@^5.0.1: dependencies: brace-expansion "^2.0.1" -minimatch@^9.0.1: - version "9.0.3" - resolved "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz" - integrity sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg== - dependencies: - brace-expansion "^2.0.1" - -minimatch@9.0.3: - version "9.0.3" - resolved "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz" - integrity sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg== - dependencies: - brace-expansion "^2.0.1" - minimist@^1.2.0, minimist@^1.2.5, minimist@^1.2.6, minimist@^1.2.8: version "1.2.8" resolved "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz" @@ -8166,16 +8491,16 @@ minipass@^3.0.0: dependencies: yallist "^4.0.0" -"minipass@^5.0.0 || ^6.0.2 || ^7.0.0": - version "7.0.4" - resolved "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz" - integrity sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ== - minipass@^5.0.0: version "5.0.0" resolved "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz" integrity sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ== +"minipass@^5.0.0 || ^6.0.2 || ^7.0.0": + version "7.0.4" + resolved "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz" + integrity sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ== + minizlib@^2.1.1: version "2.1.2" resolved "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz" @@ -8221,16 +8546,16 @@ mrmime@^2.0.0: resolved "https://registry.npmjs.org/mrmime/-/mrmime-2.0.0.tgz" integrity sha512-eu38+hdgojoyq63s+yTpN4XMBdt5l8HhMhc4VKLO9KM5caLIBvUm4thi7fFaxyTmCKeNnXZ5pAlBwCUnhA09uw== -ms@^2.1.1, ms@2.1.2: - version "2.1.2" - resolved "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz" - integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== - ms@2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz" integrity sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A== +ms@2.1.2, ms@^2.1.1: + version "2.1.2" + resolved "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz" + integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== + ms@2.1.3: version "2.1.3" resolved "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz" @@ -8550,14 +8875,7 @@ os-tmpdir@~1.0.2: resolved "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz" integrity sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g== -p-limit@^2.0.0: - version "2.3.0" - resolved "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz" - integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w== - dependencies: - p-try "^2.0.0" - -p-limit@^2.2.0: +p-limit@^2.0.0, p-limit@^2.2.0: version "2.3.0" resolved "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz" integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w== @@ -8810,7 +9128,7 @@ pkg-types@^1.0.3: mlly "^1.2.0" pathe "^1.1.0" -playwright-core@>=1.2.0, playwright-core@1.40.1: +playwright-core@1.40.1, playwright-core@>=1.2.0: version "1.40.1" resolved "https://registry.npmjs.org/playwright-core/-/playwright-core-1.40.1.tgz" integrity sha512-+hkOycxPiV534c4HhpfX6yrlawqVUzITRKwHAmYfmsVreltEl6fAZJ3DPfLMOODw0H3s1Itd6MDCWmP1fl/QvQ== @@ -9001,13 +9319,6 @@ pure-rand@^6.0.0: resolved "https://registry.npmjs.org/pure-rand/-/pure-rand-6.0.4.tgz" integrity sha512-LA0Y9kxMYv47GIPJy6MI84fqTd2HmYZI83W/kM/SkKfDlajnZYfmXFTxkbY+xSBPkLJxltMa9hIkmdc29eguMA== -qs@^6.10.0: - version "6.11.2" - resolved "https://registry.npmjs.org/qs/-/qs-6.11.2.tgz" - integrity sha512-tDNIz22aBzCDxLtVH++VnTfzxlfeK5CbqohpSqpJgj1Wg/cQbStNAz3NuqCs5vV+pjBsK4x4pN9HlVh7rcYRiA== - dependencies: - side-channel "^1.0.4" - qs@6.11.0: version "6.11.0" resolved "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz" @@ -9015,6 +9326,13 @@ qs@6.11.0: dependencies: side-channel "^1.0.4" +qs@^6.10.0: + version "6.11.2" + resolved "https://registry.npmjs.org/qs/-/qs-6.11.2.tgz" + integrity sha512-tDNIz22aBzCDxLtVH++VnTfzxlfeK5CbqohpSqpJgj1Wg/cQbStNAz3NuqCs5vV+pjBsK4x4pN9HlVh7rcYRiA== + dependencies: + side-channel "^1.0.4" + querystringify@^2.1.1: version "2.2.0" resolved "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz" @@ -9098,7 +9416,7 @@ react-docgen@^7.0.0: resolve "^1.22.1" strip-indent "^4.0.0" -"react-dom@^0.14.8 || ^15.0.1 || ^16.0.0 || ^17.0.1 || ^18.0.0", "react-dom@^16.8 || ^17.0 || ^18.0", "react-dom@^16.8.0 || ^17.0.0 || ^18.0.0", "react-dom@^17.0.0 || ^18.0.0", react-dom@^18.0.0, react-dom@^18.2.0, react-dom@>=16.6.0, react-dom@>=16.8, react-dom@>=16.8.0, "react-dom@16.8.0 - 18": +react-dom@^18.2.0: version "18.2.0" resolved "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz" integrity sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g== @@ -9120,7 +9438,7 @@ react-gtm-module@^2.0.11: resolved "https://registry.npmjs.org/react-gtm-module/-/react-gtm-module-2.0.11.tgz" integrity sha512-8gyj4TTxeP7eEyc2QKawEuQoAZdjKvMY4pgWfycGmqGByhs17fR+zEBs0JUDq4US/l+vbTl+6zvUIx27iDo/Vw== -react-hook-form@^7.0.0, react-hook-form@^7.47.0: +react-hook-form@^7.47.0: version "7.48.2" resolved "https://registry.npmjs.org/react-hook-form/-/react-hook-form-7.48.2.tgz" integrity sha512-H0T2InFQb1hX7qKtDIZmvpU1Xfn/bdahWBN1fH19gSe4bBEqTfmlr7H3XWTaVtiK4/tpPaI1F3355GPMZYge+A== @@ -9133,12 +9451,12 @@ react-i18next@^14.0.1: "@babel/runtime" "^7.22.5" html-parse-stringify "^3.0.1" -react-is@^16.13.1: - version "16.13.1" - resolved "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz" - integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== +react-is@18.1.0: + version "18.1.0" + resolved "https://registry.npmjs.org/react-is/-/react-is-18.1.0.tgz" + integrity sha512-Fl7FuabXsJnV5Q1qIOQwx/sagGF18kogb4gpfcG4gjLBWO0WDiiz1ko/ExayuxE7InyQkBLkxRFG5oxY6Uu3Kg== -react-is@^16.7.0: +react-is@^16.13.1, react-is@^16.7.0: version "16.13.1" resolved "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz" integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== @@ -9153,11 +9471,6 @@ react-is@^18.0.0, react-is@^18.2.0: resolved "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz" integrity sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w== -react-is@18.1.0: - version "18.1.0" - resolved "https://registry.npmjs.org/react-is/-/react-is-18.1.0.tgz" - integrity sha512-Fl7FuabXsJnV5Q1qIOQwx/sagGF18kogb4gpfcG4gjLBWO0WDiiz1ko/ExayuxE7InyQkBLkxRFG5oxY6Uu3Kg== - react-json-tree@^0.18.0: version "0.18.0" resolved "https://registry.npmjs.org/react-json-tree/-/react-json-tree-0.18.0.tgz" @@ -9234,7 +9547,7 @@ react-transition-group@^4.4.5: loose-envify "^1.4.0" prop-types "^15.6.2" -"react@^0.14.8 || ^15.0.1 || ^16.0.0 || ^17.0.1 || ^18.0.0", "react@^16.3.0 || ^17.0.1 || ^18.0.0", "react@^16.8 || ^17.0 || ^18.0", "react@^16.8.0 || ^17 || ^18", "react@^16.8.0 || ^17.0.0 || ^18.0.0", "react@^17.0.0 || ^18.0.0", react@^18.0.0, react@^18.2.0, "react@>= 0.14.0", "react@>= 16.8.0", react@>=16, react@>=16.6.0, react@>=16.8, react@>=16.8.0, "react@15.x || 16.x || 17.x || 18.x", "react@16.8.0 - 18": +react@^18.2.0: version "18.2.0" resolved "https://registry.npmjs.org/react/-/react-18.2.0.tgz" integrity sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ== @@ -9273,16 +9586,7 @@ readable-stream@^2.0.0, readable-stream@^2.2.2, readable-stream@~2.3.6: string_decoder "~1.1.1" util-deprecate "~1.0.1" -readable-stream@^3.1.1: - version "3.6.2" - resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz" - integrity sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA== - dependencies: - inherits "^2.0.3" - string_decoder "^1.1.1" - util-deprecate "^1.0.1" - -readable-stream@^3.4.0: +readable-stream@^3.1.1, readable-stream@^3.4.0: version "3.6.2" resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz" integrity sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA== @@ -9496,27 +9800,20 @@ reusify@^1.0.4: resolved "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz" integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== -rimraf@^2.6.1: - version "2.7.1" - resolved "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz" - integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w== +rimraf@3.0.2, rimraf@^3.0.0, rimraf@^3.0.2: + version "3.0.2" + resolved "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz" + integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== dependencies: glob "^7.1.3" -rimraf@^2.6.3: +rimraf@^2.6.1, rimraf@^2.6.3: version "2.7.1" resolved "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz" integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w== dependencies: glob "^7.1.3" -rimraf@^3.0.0, rimraf@^3.0.2, rimraf@3.0.2: - version "3.0.2" - resolved "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz" - integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== - dependencies: - glob "^7.1.3" - rimraf@~2.6.2: version "2.6.3" resolved "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz" @@ -9524,7 +9821,7 @@ rimraf@~2.6.2: dependencies: glob "^7.1.3" -rollup@^1.20.0||^2.0.0||^3.0.0||^4.0.0, "rollup@^2.25.0 || ^3.3.0", rollup@^3.27.1: +"rollup@^2.25.0 || ^3.3.0", rollup@^3.27.1: version "3.29.4" resolved "https://registry.npmjs.org/rollup/-/rollup-3.29.4.tgz" integrity sha512-oWzmBZwvYrU0iJHtDmhsm662rC15FRXmcjCk1xD771dFDx5jJ02ufAQQTn0etB2emNk4J9EZg/yWKpsn9BWGRw== @@ -9580,17 +9877,12 @@ safe-array-concat@^1.1.2: has-symbols "^1.0.3" isarray "^2.0.5" -safe-buffer@~5.1.0, safe-buffer@~5.1.1, safe-buffer@5.1.2: +safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: version "5.1.2" resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz" integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== -safe-buffer@~5.2.0: - version "5.2.1" - resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz" - integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== - -safe-buffer@5.2.1: +safe-buffer@5.2.1, safe-buffer@~5.2.0: version "5.2.1" resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz" integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== @@ -9632,22 +9924,12 @@ schema-utils@^2.7.0: ajv "^6.12.4" ajv-keywords "^3.5.2" -semver@^5.6.0: +"semver@2 || 3 || 4 || 5", semver@^5.6.0: version "5.7.2" resolved "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz" integrity sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g== -semver@^6.0.0: - version "6.3.1" - resolved "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz" - integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== - -semver@^6.3.0: - version "6.3.1" - resolved "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz" - integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== - -semver@^6.3.1: +semver@^6.0.0, semver@^6.3.0, semver@^6.3.1: version "6.3.1" resolved "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz" integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== @@ -9659,11 +9941,6 @@ semver@^7.3.7, semver@^7.5.3, semver@^7.5.4: dependencies: lru-cache "^6.0.0" -"semver@2 || 3 || 4 || 5": - version "5.7.2" - resolved "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz" - integrity sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g== - send@0.18.0: version "0.18.0" resolved "https://registry.npmjs.org/send/-/send-0.18.0.tgz" @@ -9769,12 +10046,7 @@ signal-exit@^3.0.2, signal-exit@^3.0.3, signal-exit@^3.0.7: resolved "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz" integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== -signal-exit@^4.0.1: - version "4.1.0" - resolved "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz" - integrity sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw== - -signal-exit@^4.1.0: +signal-exit@^4.0.1, signal-exit@^4.1.0: version "4.1.0" resolved "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz" integrity sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw== @@ -9827,14 +10099,6 @@ source-map-js@^1.0.2: resolved "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz" integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw== -source-map-support@^0.5.16: - version "0.5.21" - resolved "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz" - integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w== - dependencies: - buffer-from "^1.0.0" - source-map "^0.6.0" - source-map-support@0.5.13: version "0.5.13" resolved "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz" @@ -9843,6 +10107,14 @@ source-map-support@0.5.13: buffer-from "^1.0.0" source-map "^0.6.0" +source-map-support@^0.5.16: + version "0.5.21" + resolved "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz" + integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w== + dependencies: + buffer-from "^1.0.0" + source-map "^0.6.0" + source-map@^0.5.7: version "0.5.7" resolved "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz" @@ -9975,20 +10247,6 @@ stream-shift@^1.0.0: resolved "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.1.tgz" integrity sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ== -string_decoder@^1.1.1: - version "1.3.0" - resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz" - integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== - dependencies: - safe-buffer "~5.2.0" - -string_decoder@~1.1.1: - version "1.1.1" - resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz" - integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== - dependencies: - safe-buffer "~5.1.0" - string-length@^4.0.1: version "4.0.2" resolved "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz" @@ -10005,16 +10263,7 @@ string-length@^5.0.1: char-regex "^2.0.0" strip-ansi "^7.0.1" -"string-width-cjs@npm:string-width@^4.2.0": - version "4.2.3" - resolved "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz" - integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== - dependencies: - emoji-regex "^8.0.0" - is-fullwidth-code-point "^3.0.0" - strip-ansi "^6.0.1" - -string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: +"string-width-cjs@npm:string-width@^4.2.0", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: version "4.2.3" resolved "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz" integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== @@ -10078,14 +10327,21 @@ string.prototype.trimstart@^1.0.7: define-properties "^1.2.0" es-abstract "^1.22.1" -"strip-ansi-cjs@npm:strip-ansi@^6.0.1": - version "6.0.1" - resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz" - integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== +string_decoder@^1.1.1: + version "1.3.0" + resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz" + integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== dependencies: - ansi-regex "^5.0.1" + safe-buffer "~5.2.0" + +string_decoder@~1.1.1: + version "1.1.1" + resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz" + integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== + dependencies: + safe-buffer "~5.1.0" -strip-ansi@^6.0.0, strip-ansi@^6.0.1: +"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1: version "6.0.1" resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz" integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== @@ -10387,12 +10643,7 @@ tsconfig-paths@^3.15.0: minimist "^1.2.6" strip-bom "^3.0.0" -tslib@^1.13.0: - version "1.14.1" - resolved "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz" - integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== - -tslib@^1.8.1: +tslib@^1.13.0, tslib@^1.8.1: version "1.14.1" resolved "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz" integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== @@ -10421,7 +10672,7 @@ type-check@^0.4.0, type-check@~0.4.0: dependencies: prelude-ls "^1.2.1" -type-detect@^4.0.0, type-detect@^4.0.8, type-detect@4.0.8: +type-detect@4.0.8, type-detect@^4.0.0, type-detect@^4.0.8: version "4.0.8" resolved "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz" integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g== @@ -10446,12 +10697,7 @@ type-fest@^0.6.0: resolved "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz" integrity sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg== -type-fest@^0.8.0: - version "0.8.1" - resolved "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz" - integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA== - -type-fest@^0.8.1: +type-fest@^0.8.0, type-fest@^0.8.1: version "0.8.1" resolved "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz" integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA== @@ -10530,7 +10776,7 @@ typedarray@^0.0.6: resolved "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz" integrity sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA== -typescript@*, typescript@^5.0.2, "typescript@>= 4.3.x", "typescript@>=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta", typescript@>=4.2.0: +typescript@^5.0.2: version "5.3.2" resolved "https://registry.npmjs.org/typescript/-/typescript-5.3.2.tgz" integrity sha512-6l+RyNy7oAHDfxC4FzSJcz9vnjTKxrLpDG5M2Vu4SHRVNg6xzqZp6LYSR9zjqQTu8DU/f5xwxUdADOkbrIX2gQ== @@ -10637,7 +10883,7 @@ unload@2.2.0: "@babel/runtime" "^7.6.2" detect-node "^2.0.4" -unpipe@~1.0.0, unpipe@1.0.0: +unpipe@1.0.0, unpipe@~1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz" integrity sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ== @@ -10776,7 +11022,7 @@ vite-plugin-istanbul@^3.0.1: picocolors "^1.0.0" test-exclude "^6.0.0" -"vite@^3.0.0 || ^4.0.0 || ^5.0.0", vite@^4, vite@^4.1.0-beta.0, "vite@^4.2.0 || ^5.0.0", vite@^4.3.9: +vite@^4.3.9: version "4.5.1" resolved "https://registry.npmjs.org/vite/-/vite-4.5.1.tgz" integrity sha512-AXXFaAJ8yebyqzoNB9fu2pHoo/nWX+xZlaRwoeYUxEqBO+Zj4msE5G+BhGBll9lYEKv9Hfks52PAF2X7qDYXQA== @@ -10798,7 +11044,7 @@ vite@^5.0.0: optionalDependencies: fsevents "~2.3.3" -vitest@^1.0.0, vitest@^1.1.0, "vitest@>= 0.32": +vitest@^1.1.0: version "1.2.2" resolved "https://registry.npmjs.org/vitest/-/vitest-1.2.2.tgz" integrity sha512-d5Ouvrnms3GD9USIK36KG8OZ5bEvKEkITFtnGv56HFaSlbItJuYr7hv2Lkn903+AvRAgSixiamozUVfORUekjw== @@ -10879,7 +11125,7 @@ wcwidth@^1.0.1: dependencies: defaults "^1.0.3" -web-streams-polyfill@^3.0.3, web-streams-polyfill@>=3.2.1: +web-streams-polyfill@^3.0.3: version "3.3.3" resolved "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz" integrity sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw== @@ -11014,7 +11260,7 @@ wordwrap@^1.0.0: resolved "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz" integrity sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q== -"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0": +"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0", wrap-ansi@^7.0.0: version "7.0.0" resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz" integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== @@ -11032,15 +11278,6 @@ wrap-ansi@^6.2.0: string-width "^4.1.0" strip-ansi "^6.0.0" -wrap-ansi@^7.0.0: - version "7.0.0" - resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz" - integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== - dependencies: - ansi-styles "^4.0.0" - string-width "^4.1.0" - strip-ansi "^6.0.0" - wrap-ansi@^8.1.0: version "8.1.0" resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz"