From 3aff981bc16287e1729a07bebf582c69d460888e Mon Sep 17 00:00:00 2001 From: Harman-singh-waraich Date: Mon, 16 Dec 2024 22:39:16 +0530 Subject: [PATCH 1/4] feat(web): starred-cases --- web/src/assets/svgs/icons/star.svg | 1 + web/src/components/CaseStarButton.tsx | 55 +++++++++++++++ web/src/components/FavoriteCases.tsx | 81 +++++++++++++++++++++++ web/src/hooks/useStarredCases.tsx | 26 ++++++++ web/src/pages/Cases/CaseDetails/index.tsx | 14 +++- web/src/pages/Dashboard/index.tsx | 8 ++- 6 files changed, 179 insertions(+), 6 deletions(-) create mode 100644 web/src/assets/svgs/icons/star.svg create mode 100644 web/src/components/CaseStarButton.tsx create mode 100644 web/src/components/FavoriteCases.tsx create mode 100644 web/src/hooks/useStarredCases.tsx diff --git a/web/src/assets/svgs/icons/star.svg b/web/src/assets/svgs/icons/star.svg new file mode 100644 index 000000000..055e853c0 --- /dev/null +++ b/web/src/assets/svgs/icons/star.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/components/CaseStarButton.tsx b/web/src/components/CaseStarButton.tsx new file mode 100644 index 000000000..c827ba4f7 --- /dev/null +++ b/web/src/components/CaseStarButton.tsx @@ -0,0 +1,55 @@ +import React, { useMemo } from "react"; +import styled, { css } from "styled-components"; + +import { Button, Tooltip } from "@kleros/ui-components-library"; + +import Star from "svgs/icons/star.svg"; + +import useIsDesktop from "hooks/useIsDesktop"; +import useStarredCases from "hooks/useStarredCases"; + +const StyledButton = styled(Button)<{ starred: boolean }>` + background: none; + padding: 0 0 2px 0; + + .button-svg { + width: 24px; + height: 24px; + margin: 0; + fill: none; + + path { + stroke: ${({ theme }) => theme.secondaryPurple}; + } + ${({ starred }) => + starred && + css` + fill: ${({ theme }) => theme.secondaryPurple}; + `}; + } + + :hover { + background: none; + } +`; + +const CaseStarButton: React.FC<{ id: string }> = ({ id }) => { + const { starredCases, starCase } = useStarredCases(); + const isDesktop = useIsDesktop(); + const starred = useMemo(() => Boolean(starredCases.get(id)), [id, starredCases]); + return ( + + { + e.stopPropagation(); + starCase(id); + }} + /> + + ); +}; + +export default CaseStarButton; diff --git a/web/src/components/FavoriteCases.tsx b/web/src/components/FavoriteCases.tsx new file mode 100644 index 000000000..44ce19065 --- /dev/null +++ b/web/src/components/FavoriteCases.tsx @@ -0,0 +1,81 @@ +import React, { useMemo, useState } from "react"; +import styled from "styled-components"; + +import { StandardPagination } from "@kleros/ui-components-library"; + +import useStarredCases from "hooks/useStarredCases"; +import { isUndefined } from "utils/index"; + +import { DisputeDetailsFragment, useCasesQuery } from "queries/useCasesQuery"; + +import { responsiveSize } from "styles/responsiveSize"; + +import DisputeView from "components/DisputeView"; +import { SkeletonDisputeCard } from "components/StyledSkeleton"; + +const Container = styled.div` + margin-top: ${responsiveSize(48, 80)}; +`; + +const Title = styled.h1` + margin-bottom: 12px; +`; + +const DisputeContainer = styled.div` + --gap: 16px; + display: grid; + grid-template-columns: repeat(auto-fill, minmax(min(100%, max(312px, (100% - var(--gap) * 2)/3)), 1fr)); + align-items: stretch; + gap: var(--gap); +`; + +const StyledLabel = styled.label` + display: block; + color: ${({ theme }) => theme.primaryBlue}; + cursor: pointer; + margin-bottom: ${responsiveSize(16, 32)}; + :hover { + color: ${({ theme }) => theme.secondaryBlue}; + } +`; + +const StyledPagination = styled(StandardPagination)` + margin-top: 24px; + margin-left: auto; + margin-right: auto; +`; + +const FavoriteCases: React.FC = () => { + const { starredCaseIds, clearAll } = useStarredCases(); + + const [currentPage, setCurrentPage] = useState(1); + const casesPerPage = 3; + const totalPages = Math.ceil(starredCaseIds.length / casesPerPage); + + const { data } = useCasesQuery((currentPage - 1) * casesPerPage, casesPerPage, { + id_in: starredCaseIds, + }); + + const disputes: DisputeDetailsFragment[] = useMemo(() => data?.disputes as DisputeDetailsFragment[], [data]); + + return starredCaseIds.length > 0 && (isUndefined(disputes) || disputes.length > 0) ? ( + + Favorite Cases + Clear all + + {isUndefined(disputes) + ? Array.from({ length: 3 }).map((_, index) => ) + : disputes.map((dispute) => )} + + {totalPages > 1 ? ( + setCurrentPage(page)} + /> + ) : null} + + ) : null; +}; + +export default FavoriteCases; diff --git a/web/src/hooks/useStarredCases.tsx b/web/src/hooks/useStarredCases.tsx new file mode 100644 index 000000000..261bd5539 --- /dev/null +++ b/web/src/hooks/useStarredCases.tsx @@ -0,0 +1,26 @@ +import { useMemo } from "react"; + +import { useLocalStorage } from "./useLocalStorage"; + +const useStarredCases = () => { + const initialValue = new Map(); + + const [localStarredCases, setLocalStarredCases] = useLocalStorage("starredCases", Array.from(initialValue)); + + const starredCases = useMemo(() => new Map(localStarredCases), [localStarredCases]); + const starredCaseIds = Array.from(starredCases.keys()); + + const starCase = (id: string) => { + if (starredCases.get(id)) starredCases.delete(id); + else starredCases.set(id, true); + + setLocalStarredCases(Array.from(starredCases)); + }; + + const clearAll = () => { + setLocalStarredCases(Array.from(initialValue)); + }; + return { starredCases, starredCaseIds, starCase, clearAll }; +}; + +export default useStarredCases; diff --git a/web/src/pages/Cases/CaseDetails/index.tsx b/web/src/pages/Cases/CaseDetails/index.tsx index 643eb696d..e4586f531 100644 --- a/web/src/pages/Cases/CaseDetails/index.tsx +++ b/web/src/pages/Cases/CaseDetails/index.tsx @@ -12,6 +12,9 @@ import { useDisputeDetailsQuery } from "queries/useDisputeDetailsQuery"; import { responsiveSize } from "styles/responsiveSize"; +import CaseStarButton from "components/CaseStarButton"; +import ScrollTop from "components/ScrollTop"; + import Appeal from "./Appeal"; import Evidence from "./Evidence"; import MaintenanceButtons from "./MaintenanceButtons"; @@ -19,7 +22,6 @@ import Overview from "./Overview"; import Tabs from "./Tabs"; import Timeline from "./Timeline"; import Voting from "./Voting"; -import ScrollTop from "components/ScrollTop"; const Container = styled.div``; @@ -37,8 +39,11 @@ const HeaderContainer = styled.div` `; const Header = styled.h1` - margin: 0; + display: flex; + align-items: center; flex: 1; + gap: 8px; + margin: 0; `; const CaseDetails: React.FC = () => { @@ -52,7 +57,10 @@ const CaseDetails: React.FC = () => { -
Case #{id}
+
+ Case #{id} {id ? : null} +
+
diff --git a/web/src/pages/Dashboard/index.tsx b/web/src/pages/Dashboard/index.tsx index 5aa271d7e..f479310f3 100644 --- a/web/src/pages/Dashboard/index.tsx +++ b/web/src/pages/Dashboard/index.tsx @@ -1,9 +1,6 @@ import React, { useMemo } from "react"; import styled from "styled-components"; -import { MAX_WIDTH_LANDSCAPE } from "styles/landscapeStyle"; -import { responsiveSize } from "styles/responsiveSize"; - import { useNavigate, useParams } from "react-router-dom"; import { useAccount } from "wagmi"; @@ -15,8 +12,12 @@ import { useUserQuery } from "queries/useUser"; import { OrderDirection } from "src/graphql/graphql"; +import { MAX_WIDTH_LANDSCAPE } from "styles/landscapeStyle"; +import { responsiveSize } from "styles/responsiveSize"; + import CasesDisplay from "components/CasesDisplay"; import ConnectWallet from "components/ConnectWallet"; +import FavoriteCases from "components/FavoriteCases"; import ScrollTop from "components/ScrollTop"; import Courts from "./Courts"; @@ -94,6 +95,7 @@ const Dashboard: React.FC = () => { )} +
); From 3785d5a90d009671a92266f033c42e15e1efada6 Mon Sep 17 00:00:00 2001 From: Harman-singh-waraich Date: Mon, 16 Dec 2024 22:51:13 +0530 Subject: [PATCH 2/4] refactor(web): rabbit-feedback --- web/src/components/CaseStarButton.tsx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/web/src/components/CaseStarButton.tsx b/web/src/components/CaseStarButton.tsx index c827ba4f7..0f83e7cc5 100644 --- a/web/src/components/CaseStarButton.tsx +++ b/web/src/components/CaseStarButton.tsx @@ -37,12 +37,15 @@ const CaseStarButton: React.FC<{ id: string }> = ({ id }) => { const { starredCases, starCase } = useStarredCases(); const isDesktop = useIsDesktop(); const starred = useMemo(() => Boolean(starredCases.get(id)), [id, starredCases]); + const text = starred ? "Remove from favorite" : "Add to favorite"; return ( - + { e.stopPropagation(); starCase(id); From f5e6562b47cb039228940d2065e54cf38a69a2b3 Mon Sep 17 00:00:00 2001 From: Harman-singh-waraich Date: Tue, 17 Dec 2024 16:51:31 +0530 Subject: [PATCH 3/4] refactor(web): use-set-to-store-favorite-case-ids --- web/src/components/CaseStarButton.tsx | 2 +- web/src/hooks/useStarredCases.tsx | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/web/src/components/CaseStarButton.tsx b/web/src/components/CaseStarButton.tsx index 0f83e7cc5..09816f563 100644 --- a/web/src/components/CaseStarButton.tsx +++ b/web/src/components/CaseStarButton.tsx @@ -36,7 +36,7 @@ const StyledButton = styled(Button)<{ starred: boolean }>` const CaseStarButton: React.FC<{ id: string }> = ({ id }) => { const { starredCases, starCase } = useStarredCases(); const isDesktop = useIsDesktop(); - const starred = useMemo(() => Boolean(starredCases.get(id)), [id, starredCases]); + const starred = useMemo(() => Boolean(starredCases.has(id)), [id, starredCases]); const text = starred ? "Remove from favorite" : "Add to favorite"; return ( diff --git a/web/src/hooks/useStarredCases.tsx b/web/src/hooks/useStarredCases.tsx index 261bd5539..eb6109306 100644 --- a/web/src/hooks/useStarredCases.tsx +++ b/web/src/hooks/useStarredCases.tsx @@ -3,16 +3,16 @@ import { useMemo } from "react"; import { useLocalStorage } from "./useLocalStorage"; const useStarredCases = () => { - const initialValue = new Map(); + const initialValue = new Set(); const [localStarredCases, setLocalStarredCases] = useLocalStorage("starredCases", Array.from(initialValue)); - const starredCases = useMemo(() => new Map(localStarredCases), [localStarredCases]); + const starredCases = useMemo(() => new Set(localStarredCases), [localStarredCases]); const starredCaseIds = Array.from(starredCases.keys()); const starCase = (id: string) => { - if (starredCases.get(id)) starredCases.delete(id); - else starredCases.set(id, true); + if (starredCases.has(id)) starredCases.delete(id); + else starredCases.add(id); setLocalStarredCases(Array.from(starredCases)); }; From 165bfdc645314ddd2b4e03d26f9cb8cb99180666 Mon Sep 17 00:00:00 2001 From: Harman-singh-waraich Date: Tue, 17 Dec 2024 16:59:47 +0530 Subject: [PATCH 4/4] refactor(web): update-favorite-cases-style --- web/src/components/CaseStarButton.tsx | 2 +- web/src/components/FavoriteCases.tsx | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/web/src/components/CaseStarButton.tsx b/web/src/components/CaseStarButton.tsx index 09816f563..1ba097686 100644 --- a/web/src/components/CaseStarButton.tsx +++ b/web/src/components/CaseStarButton.tsx @@ -39,7 +39,7 @@ const CaseStarButton: React.FC<{ id: string }> = ({ id }) => { const starred = useMemo(() => Boolean(starredCases.has(id)), [id, starredCases]); const text = starred ? "Remove from favorite" : "Add to favorite"; return ( - + theme.primaryBlue}; cursor: pointer; - margin-bottom: ${responsiveSize(16, 32)}; + margin-bottom: ${responsiveSize(12, 16)}; :hover { color: ${({ theme }) => theme.secondaryBlue}; }