From b19c3fe58988fa95b382a567bd86f7a32b132c87 Mon Sep 17 00:00:00 2001 From: pavloMandryk Date: Fri, 12 Aug 2022 12:38:12 +0200 Subject: [PATCH 1/5] feat: add entries filters --- app/App.tsx | 25 +- .../EntriesFilters/DateRangeCustom/index.tsx | 42 ++ .../EntriesFilters/DateRangeCustom/style.css | 26 ++ app/components/EntriesFilters/index.tsx | 383 ++++++++++++++++++ app/hooks/useOutsideAlerter.ts | 21 + app/providers/FnEntriesFilters.tsx | 202 +++++++++ app/routes/entries/index.tsx | 44 +- package.json | 4 + 8 files changed, 732 insertions(+), 15 deletions(-) create mode 100644 app/components/EntriesFilters/DateRangeCustom/index.tsx create mode 100644 app/components/EntriesFilters/DateRangeCustom/style.css create mode 100644 app/components/EntriesFilters/index.tsx create mode 100644 app/hooks/useOutsideAlerter.ts create mode 100644 app/providers/FnEntriesFilters.tsx diff --git a/app/App.tsx b/app/App.tsx index 2467250..faa41d5 100644 --- a/app/App.tsx +++ b/app/App.tsx @@ -7,6 +7,7 @@ import Wagmi from "~/providers/Wagmi"; import { AppLayout } from "~/components/AppLayout"; import { Outlet } from "@remix-run/react"; import { RosetteStone } from "./providers/RosetteStone"; +import { FnEntriesFilters } from "./providers/FnEntriesFilters"; export type AppContext = { displayTopBar(display: boolean): void; @@ -24,17 +25,19 @@ export const App = () => { - - - + + + + + diff --git a/app/components/EntriesFilters/DateRangeCustom/index.tsx b/app/components/EntriesFilters/DateRangeCustom/index.tsx new file mode 100644 index 0000000..f9eb0d4 --- /dev/null +++ b/app/components/EntriesFilters/DateRangeCustom/index.tsx @@ -0,0 +1,42 @@ +import React, { useRef } from "react"; +import { DateRange } from "react-date-range"; +import styled from "styled-components"; +import { useOnClickOutside } from "~/hooks/useOutsideAlerter"; + +const DateRangeCustom = ({ + show, + setShow, + onChange, + ranges = [{ startDate: new Date(), endDate: new Date(), key: "selection" }], +}: any) => { + const ref = useRef(); + + const handleClose = React.useCallback(() => { + setShow(false); + }, [setShow]); + + useOnClickOutside(ref, handleClose); + + return ( + show && ( + + + + ) + ); +}; + +const DateRangeContainer = styled.div` + z-index: 1; + position: absolute; + margin-left: auto; + margin-right: auto; + background-color: rgba(0, 0, 0, 1); + text-align: center; +`; + +export default DateRangeCustom; diff --git a/app/components/EntriesFilters/DateRangeCustom/style.css b/app/components/EntriesFilters/DateRangeCustom/style.css new file mode 100644 index 0000000..177057e --- /dev/null +++ b/app/components/EntriesFilters/DateRangeCustom/style.css @@ -0,0 +1,26 @@ +.rdrCalendarWrapper { + background-color: #FDE9BC; + border: 2px solid #CFC7B5; + border-radius: 12px; +} + +.rdrDateDisplayWrapper { + background-color: #A2957A; + border-radius: 10px 10px 0 0 ; +} + +.rdrDateDisplayItemActive { + border: 2px solid #F86E38; +} + +.rdrDateDisplayItem input { + background-color: #2B2727; + color: #FDE9BC; + font-size: 16px; + border-radius: 3px; +} + +.rdrDateDisplayItem { + box-shadow: none; + background-color: transparent; +} \ No newline at end of file diff --git a/app/components/EntriesFilters/index.tsx b/app/components/EntriesFilters/index.tsx new file mode 100644 index 0000000..4185395 --- /dev/null +++ b/app/components/EntriesFilters/index.tsx @@ -0,0 +1,383 @@ +import React from "react"; +import { + Button, + GU, + SearchInput, + TextInput, + useTheme, +} from "@blossom-labs/rosette-ui"; +import styled from "styled-components"; +import Select from "react-select"; +import DateRangeCustom from "~/components/EntriesFilters/DateRangeCustom"; +import { useOnClickOutside } from "~/hooks/useOutsideAlerter"; + +export function EntriesFilters({ + externalFilters, + internalFilters, + clearValues, + compactMode, + tabletMode, +}: { + externalFilters: any; + internalFilters: any; + clearValues: any; + compactMode: any; + tabletMode: any; +}) { + const theme = useTheme(); + const [toggleDate, setToggleDate] = React.useState(false); + + const { submitterFilter, statusFilter, dateRangeFilter, searchFilter } = + externalFilters; + + const { sortingOption } = internalFilters; + + const [submitterFilterValue, setSubmitterFilter] = submitterFilter; + const [, setStatusFilter, statusRef] = statusFilter; + const [dateRange, setDateRange] = dateRangeFilter; + const [search, setSearch] = searchFilter; + + const [, setSorting, sortingRef] = sortingOption; + + const handleStatusFilterChange = (selected: any) => { + if (selected) { + setStatusFilter(selected.value); + } + }; + + const handleSortingOptionChange = (selected: any) => { + if (selected) { + setSorting(selected.value); + } + }; + + const handleSubmitterFilterChange = (e: any) => { + setSubmitterFilter(e.target.value); + }; + + const handleDateRangeChange = (ranges: any) => { + if (ranges.selection) { + setDateRange({ + startDate: ranges.selection.startDate, + endDate: ranges.selection.endDate, + active: true, + }); + } + if (ranges.range1) { + setDateRange({ + startDate: ranges.range1.startDate, + endDate: ranges.range1.endDate, + active: true, + }); + } + }; + + return ( + + + + + + + + + + + + + + ) + case 'added': + return ( + + ) + case 'pending': + return ( +
+ Timer +
+ ) + } + } + + return ( + + + + {currentStatus} + + + {renderDynamicSection()} + + + ); +}; + +const StatusContainer = styled.div` + display: flex; + flex-direction: column; + gap: ${2 * GU}px; + padding: ${1 * GU}px; +` +const DynamicSection = styled.div` + display: flex; + flex-direction: column; + width: ${35 * GU}px; + margin: auto; +` + +const Label = styled.div` + font-size: 16px; + color: #A2957A; + margin-left: ${4 * GU}px; + margin-top: ${3 * GU}px; +` +const StatusTitle = styled.div` + font-weight: 400; + font-size: 20px; + color: #FDE9BC; + margin-left: ${4 * GU}px; + ` + +const Container = styled.div` + display: flex; + flex-direction: column; + width: 363px; + height: 200px; + justify-content: space-around; + border: 1px solid #8A8069; + border-radius: 20px; + outline: 0; +`; diff --git a/app/routes/entries/$entry.tsx b/app/routes/entries/$entry.tsx index db431bf..59f47b6 100644 --- a/app/routes/entries/$entry.tsx +++ b/app/routes/entries/$entry.tsx @@ -1,10 +1,32 @@ +import { + BackButton, + textStyle, + IdentityBadge, + GU, + useViewport, +} from "@blossom-labs/rosette-ui"; +import { useEffect, useState } from "react"; import type { LoaderFunction } from "@remix-run/node"; import { json } from "@remix-run/node"; -import { useLoaderData } from "@remix-run/react"; +import { useLoaderData, useNavigate } from "@remix-run/react"; import styled from "styled-components"; import { AppScreen } from "~/components/AppLayout/AppScreen"; -import type { FnEntrySubgraphData } from "~/types"; +import { StatusModule } from "~/components/EntryScreen/StatusModule"; +import type { FnEntryMetadata, FnEntrySubgraphData } from "~/types"; import { fetchFnEntry } from "~/utils/server/subgraph.server"; +import { fetchEntryMetadata } from "~/utils/server/entries-data.server"; + +function formatRawDate(rawDate: Date) { + const string = rawDate.toString(); + const dateArray = string.split(" "); + const formattedDate = `${dateArray[1]} ${dateArray[2]}, ${dateArray[3]}`; + return formattedDate; +} + +function formatAbi(abi: string) { + const formattedAbi = abi.replace("function ", ""); + return formattedAbi; +} export const loader: LoaderFunction = async ({ params }) => { const entryId = params.entry; @@ -18,28 +40,146 @@ export const loader: LoaderFunction = async ({ params }) => { const entry = await fetchFnEntry(entryId); - return json({ entry }); + if (!entry) { + throw new Response("Entry not found", { + status: 404, + statusText: "Entry not found", + }); + } + + const entryMetadata = await fetchEntryMetadata(entry.cid); + + if (entryMetadata.abi) { + const abi = formatAbi(entryMetadata.abi); + entryMetadata.abi = abi; + } + + return json({ entry, entryMetadata }); }; type LoaderData = { entry?: FnEntrySubgraphData; + entryMetadata?: FnEntryMetadata; }; export default function EntryRoute() { - const { entry } = useLoaderData(); + const { entry, entryMetadata } = useLoaderData(); + const navigate = useNavigate(); + const [date, setDate] = useState(); + const { below } = useViewport(); + const compactMode = below("large"); + + useEffect(() => { + if (entry) { + const rawDate = new Date(entry.upsertAt); + setDate(formatRawDate(rawDate)); + } + }, [entry]); return ( - {entry?.sigHash} + + + navigate(`/entries`)} /> + {entryMetadata?.abi} + {`Contract ${""}`} + {`Publicated on ${date?.toString()}`} + + Submitter + + + + Description + {entryMetadata?.notice} + + + + ); } -const Container = styled.div` +const DescriptionContainer = styled.div` display: flex; - justify-content: center; + flex-direction: column; +`; + +const DescriptionContent = styled.div` + font-family: "Avenir"; + font-style: normal; + font-weight: 400; + font-size: 20px; + line-height: 32px; + color: #fde9bc; +`; + +const DescriptionTitle = styled.div` + display: flex; + justify-content: start; + align-items: start; + height: 100%; + width: 100%; + color: #a2957a; + font-weight: 400; + font-size: 24px; + line-height: 24px; +`; + +const SubmitterTitle = styled.div` + font-weight: 400; + font-size: 16px; + line-height: 24px; + color: ${({ theme }) => theme.border}; + margin-bottom: ${1 * GU}px; +`; + +const SubmitterContainer = styled.div` + display: flex; + flex-direction: column; + margin-top: ${4 * GU}px; + margin-bottom: ${4 * GU}px; +`; + +const DateTitle = styled.div` + ${textStyle("title3")}; + color: ${({ theme }) => theme.border}; +`; + +const ContractTitle = styled.div` + display: flex; + justify-content: start; align-items: start; height: 100%; width: 100%; color: ${({ theme }) => theme.content}; + font-weight: 400; + font-size: 20px; + line-height: 24px; +`; +const EntryTitle = styled.div` +font-weight: 400; +font-size: 36px; +color: ${({ theme }) => theme.content};}; +`; + +const EntryInfoContainer = styled.div` + display: flex; + flex-direction: column; + justify-content: start; + align-items: start; +`; + +const EntryContainer = styled.div<{ + compactMode: boolean; + tabletMode: boolean; +}>` + display: flex; + flex-direction: ${({ compactMode }) => (compactMode ? "column" : "row")}; + grid-gap: ${({ compactMode }) => (compactMode ? 10 * GU : 30 * GU)}px; + justify-content: center; + align-items: ${({ compactMode }) => (compactMode ? "center" : "start")}; + padding-top: ${({ compactMode, tabletMode }) => + compactMode ? 3 * GU : tabletMode ? 5 * GU : 9 * GU}px; + height: 100%; + width: 100%; `; From 0466bbed468b2821c367ee0b2864627f6c39a5ef Mon Sep 17 00:00:00 2001 From: pavloMandryk Date: Mon, 15 Aug 2022 20:54:29 +0200 Subject: [PATCH 3/5] feat(entryFilters): small fixes --- app/components/EntriesFilters/index.tsx | 26 ++++++++------ app/providers/FnEntriesFilters.tsx | 46 +++++++++++++++++-------- app/routes/entries/$entry.tsx | 40 ++++++++++----------- app/routes/entries/index.tsx | 4 +-- 4 files changed, 69 insertions(+), 47 deletions(-) diff --git a/app/components/EntriesFilters/index.tsx b/app/components/EntriesFilters/index.tsx index 4185395..ddfc3ec 100644 --- a/app/components/EntriesFilters/index.tsx +++ b/app/components/EntriesFilters/index.tsx @@ -1,4 +1,4 @@ -import React from "react"; +import React, { useEffect, useRef, useState } from "react"; import { Button, GU, @@ -25,7 +25,7 @@ export function EntriesFilters({ tabletMode: any; }) { const theme = useTheme(); - const [toggleDate, setToggleDate] = React.useState(false); + const [toggleDate, setToggleDate] = useState(false); const { submitterFilter, statusFilter, dateRangeFilter, searchFilter } = externalFilters; @@ -92,7 +92,7 @@ export function EntriesFilters({