From fc29e27fcce369fefa3485a3eb3ddd206880207c Mon Sep 17 00:00:00 2001 From: dcodes05 Date: Sat, 9 Sep 2023 19:53:01 +0200 Subject: [PATCH] feat: history table redesign --- .eslintrc.json | 1 + .graphqlconfig | 2 +- apps/oeth/src/App.tsx | 14 +- .../history/src/components/APYContainer.tsx | 66 +++++++ .../history/src/components/ExportData.tsx | 46 +++++ libs/oeth/history/src/components/Filters.tsx | 177 ++++++++++++++++++ .../history/src/components/HistoryButton.tsx | 40 +--- .../history/src/components/HistoryCard.tsx | 118 ++++++------ .../history/src/components/HistoryTable.tsx | 127 ++++++++----- libs/oeth/history/src/queries.generated.tsx | 132 +++++++++++-- libs/oeth/history/src/queries.graphql | 43 ++++- libs/oeth/history/src/views/HistoryView.tsx | 13 +- libs/oeth/history/tsconfig.lib.json | 8 +- libs/oeth/shared/src/generated/graphql.ts | 104 +++++++++- libs/oeth/swap/src/components/GasPopover.tsx | 14 +- libs/oeth/swap/src/views/SwapView.tsx | 3 + libs/shared/assets/files/download.svg | 6 + .../components/src/Checkbox/CheckboxIcon.tsx | 42 +++++ .../components/src/Checkbox/EmptyCheckbox.tsx | 25 +++ libs/shared/components/src/Checkbox/index.tsx | 2 + libs/shared/components/src/LinkIcon/index.tsx | 7 +- libs/shared/components/src/index.ts | 1 + libs/shared/theme/src/theme.tsx | 12 +- 23 files changed, 816 insertions(+), 187 deletions(-) create mode 100644 libs/oeth/history/src/components/APYContainer.tsx create mode 100644 libs/oeth/history/src/components/ExportData.tsx create mode 100644 libs/oeth/history/src/components/Filters.tsx create mode 100644 libs/shared/assets/files/download.svg create mode 100644 libs/shared/components/src/Checkbox/CheckboxIcon.tsx create mode 100644 libs/shared/components/src/Checkbox/EmptyCheckbox.tsx create mode 100644 libs/shared/components/src/Checkbox/index.tsx diff --git a/.eslintrc.json b/.eslintrc.json index 4dcc7dca2..49557a009 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -27,6 +27,7 @@ ] } ], + "@typescript-eslint/no-explicit-any": false, "react/react-in-jsx-scope": "off", "no-empty": ["error", { "allowEmptyCatch": true }], // Unused imports rules diff --git a/.graphqlconfig b/.graphqlconfig index c533f7981..37ef6aa86 100644 --- a/.graphqlconfig +++ b/.graphqlconfig @@ -1,4 +1,4 @@ { "name": "Subsquid GraphQL Schema", - "schemaPath": "https://squid.subsquid.io/origin-squid/v/v4/graphql" + "schemaPath": "https://squid.subsquid.io/origin-squid/v/v5/graphql" } diff --git a/apps/oeth/src/App.tsx b/apps/oeth/src/App.tsx index fe38e4a42..f440992b4 100644 --- a/apps/oeth/src/App.tsx +++ b/apps/oeth/src/App.tsx @@ -1,6 +1,5 @@ import { Container, Stack } from '@mui/material'; import { HistoryView } from '@origin/oeth/history'; -import { ApyHeader } from '@origin/oeth/shared'; import { SwapView } from '@origin/oeth/swap'; import { Route, Routes } from 'react-router-dom'; @@ -23,14 +22,11 @@ export function App() { }} maxWidth="sm" > - - - - } /> - } /> - } /> - - + + } /> + } /> + } /> + ); diff --git a/libs/oeth/history/src/components/APYContainer.tsx b/libs/oeth/history/src/components/APYContainer.tsx new file mode 100644 index 000000000..c2103c0db --- /dev/null +++ b/libs/oeth/history/src/components/APYContainer.tsx @@ -0,0 +1,66 @@ +import { Box, Divider, Stack, Typography } from '@mui/material'; +import { valueFormat } from '@origin/shared/components'; +import { theme } from '@origin/shared/theme'; +import React from 'react'; +import { useIntl } from 'react-intl'; + +export function APYContainer() { + const intl = useIntl(); + return ( + theme.palette.background.paper, + borderRadius: 1, + }} + direction="row" + justifyContent="space-between" + > + + + + + + + ); +} + +interface Props { + label: string; + value: number; +} + +function ValueContainer(props: Props) { + const intl = useIntl(); + return ( + + + {props.label} + + theme.typography.pxToRem(20), + fontStyle: 'normal', + fontWeight: 700, + lineHeight: '2rem', + textAlign: 'center', + }} + color="primary.contrastText" + > + {intl.formatNumber(props.value, valueFormat)} + + + ); +} diff --git a/libs/oeth/history/src/components/ExportData.tsx b/libs/oeth/history/src/components/ExportData.tsx new file mode 100644 index 000000000..1f72774aa --- /dev/null +++ b/libs/oeth/history/src/components/ExportData.tsx @@ -0,0 +1,46 @@ +import React, { useCallback, useMemo, useRef } from 'react'; + +import { Box, Link } from '@mui/material'; +import { useIntl } from 'react-intl'; + +import { HistoryFilterButton } from './HistoryButton'; +import { Rows } from './HistoryTable'; + +interface Props { + data?: Rows; +} + +export function ExportData({ data }: Props) { + const link = useRef(null); + const intl = useIntl(); + + const generateCSV = useCallback(() => { + const rows = [['Date', 'Type', 'Amount', 'Balance', 'Transaction Hash']]; + data.forEach((row) => + rows.push([row.timestamp, row.type, row.value, row.balance, row.txHash]), + ); + link.current.href = + 'data:text/csv;charset=utf-8,' + + encodeURI(rows.map((e) => e.join(',')).join('\n')); + link.current.click(); + }, [data]); + + return ( + <> + + + + {intl.formatMessage({ defaultMessage: 'CSV' })} + + + ); +} diff --git a/libs/oeth/history/src/components/Filters.tsx b/libs/oeth/history/src/components/Filters.tsx new file mode 100644 index 000000000..467971290 --- /dev/null +++ b/libs/oeth/history/src/components/Filters.tsx @@ -0,0 +1,177 @@ +import React, { useState } from 'react'; + +import { + Box, + Button, + Checkbox, + Divider, + FormControlLabel, + FormLabel, + MenuItem, + MenuList, + Popover, + Stack, + Typography, + alpha, + useTheme, +} from '@mui/material'; +import { + ActionButton, + CheckboxIcon, + EmptyCheckbox, +} from '@origin/shared/components'; +import { useIntl } from 'react-intl'; + +import { HistoryFilterButton } from './HistoryButton'; + +const styles = { + fontSize: '0.75rem', + fontWeight: 500, + lineHeight: '1.25rem', + color: 'primary.contrastText', +}; + +interface Props { + onChange: (values: string[]) => void; +} + +export function HistoryFilters({ onChange }: Props) { + const [selected, setSelectedTypes] = useState([]); + const intl = useIntl(); + const theme = useTheme(); + const [anchorEl, setAnchorEl] = useState(null); + + return ( + <> + setAnchorEl(e.currentTarget)}> + Filters + theme.palette.primary.contrastText, + }} + > + {selected.length} + + setAnchorEl(null)} + anchorOrigin={{ + vertical: 'bottom', + horizontal: 'right', + }} + transformOrigin={{ + vertical: 'top', + horizontal: 'right', + }} + sx={{ + '& .MuiPaper-root.MuiPopover-paper': { + boxSizing: 'border-box', + background: 'background-paper', + maxWidth: '16.5rem', + width: '100%', + borderRadius: 2, + [theme.breakpoints.down('md')]: { + left: '0 !important', + right: 0, + marginInline: 'auto', + }, + }, + }} + > + + {intl.formatMessage({ defaultMessage: 'Filters' })} + + + + {['Yield', 'Swap', 'Sent', 'Received'].map((label) => ( + theme.palette.grey[700], + }, + }} + > + + {label} + + + } + icon={} + sx={{ + '& svg, input': { + width: '1.25rem', + height: '1.25rem', + top: 'auto', + left: 'auto', + }, + '&:hover:has(input:checked) svg': { + fill: (theme) => alpha(theme.palette.secondary.main, 0.4), + strokeWidth: '1px', + stroke: (theme) => theme.palette.primary.main, + }, + '&:hover:has(input:not(:checked)) svg': { + fill: (theme) => alpha(theme.palette.secondary.main, 0.4), + }, + }} + onChange={(e) => + setSelectedTypes((prev) => { + if (e.target.checked) { + return [...prev, label]; + } else { + return prev.filter((val) => val !== label); + } + }) + } + /> + + ))} + + + + + { + setAnchorEl(null); + onChange(selected); + }} + > + {intl.formatMessage({ defaultMessage: 'Apply' })} + + + + + ); +} diff --git a/libs/oeth/history/src/components/HistoryButton.tsx b/libs/oeth/history/src/components/HistoryButton.tsx index b62a708fd..2d4220121 100644 --- a/libs/oeth/history/src/components/HistoryButton.tsx +++ b/libs/oeth/history/src/components/HistoryButton.tsx @@ -1,6 +1,6 @@ -import { alpha, Box, Button } from '@mui/material'; +import { alpha, Button } from '@mui/material'; -import type { BoxProps, ButtonProps } from '@mui/material'; +import type { ButtonProps } from '@mui/material'; interface Props extends ButtonProps { circle?: boolean; @@ -19,18 +19,22 @@ export function HistoryFilterButton({ ); } - -function Circle(props: BoxProps) { - return ( - theme.palette.background.default, - height: '0.5rem', - width: '0.5rem', - borderRadius: '100%', - ...props, - }} - /> - ); -} diff --git a/libs/oeth/history/src/components/HistoryCard.tsx b/libs/oeth/history/src/components/HistoryCard.tsx index c13d944c7..88351f122 100644 --- a/libs/oeth/history/src/components/HistoryCard.tsx +++ b/libs/oeth/history/src/components/HistoryCard.tsx @@ -1,73 +1,75 @@ import { useState } from 'react'; -import { Box, Button, Stack, Typography } from '@mui/material'; -import { Card } from '@origin/shared/components'; +import { Box, Button, Divider, Stack, Typography } from '@mui/material'; import { useIntl } from 'react-intl'; -import { HistoryFilterButton } from './HistoryButton'; +import { + HistoryTableDocument, + HistoryTableQuery, + HistoryTableWithFiltersDocument, +} from '../queries.generated'; +import { ExportData } from './ExportData'; +import { HistoryFilters } from './Filters'; import { HistoryTable } from './HistoryTable'; +import { graphqlClient } from '@origin/oeth/shared'; +import { useQuery } from '@tanstack/react-query'; -import type { ColumnFilter } from '@tanstack/react-table'; +const PAGE_SIZE = 20; export function HistoryCard() { - const [isConnected, setConnectionState] = useState(false); + const [page, setPage] = useState(0); + const [filters, setFilters] = useState([]); + const [isConnected, setConnectionState] = useState(true); + const { data, isFetching } = useQuery( + ['history-table', filters, page], + () => { + return graphqlClient< + HistoryTableQuery, + { addressId: string; filters?: string[] } + >( + filters.length ? HistoryTableWithFiltersDocument : HistoryTableDocument, + { + // add the address id here + addressId: '', + filters: filters.length ? filters : undefined, + offset: page * PAGE_SIZE, + }, + )(); + }, + { enabled: isConnected }, + ); + const intl = useIntl(); - const [filter, setFilter] = useState({ - id: 'type', - value: [], - }); - function filterRows(value: string) { - setFilter((prev) => { - if ((prev.value as string[]).includes(value)) { - return { - ...prev, - value: [...(prev.value as string[]).filter((val) => val !== value)], - }; - } else { - return { - ...prev, - value: [...(prev.value as string[]), value], - }; - } - }); - } return ( - - History - - {[ - intl.formatMessage({ defaultMessage: 'Received' }), - intl.formatMessage({ defaultMessage: 'Sent' }), - intl.formatMessage({ defaultMessage: 'Swap' }), - intl.formatMessage({ defaultMessage: 'Yield' }), - ].map((label) => ( - filterRows(label.toLowerCase())} - > - {label} - - ))} - - - {intl.formatMessage({ defaultMessage: 'Export CSV' })} - + + + + {intl.formatMessage({ defaultMessage: 'OETH transactions' })} + + + setFilters(values)} /> + - } - > + + {isConnected ? ( - + 0} + page={page} + setPage={(page) => setPage(page)} + /> ) : ( @@ -78,6 +80,6 @@ export function HistoryCard() { )} - + ); } diff --git a/libs/oeth/history/src/components/HistoryTable.tsx b/libs/oeth/history/src/components/HistoryTable.tsx index 2401bb7dc..ef52d18b0 100644 --- a/libs/oeth/history/src/components/HistoryTable.tsx +++ b/libs/oeth/history/src/components/HistoryTable.tsx @@ -1,8 +1,8 @@ -import { useEffect, useMemo, useState } from 'react'; +import { useMemo } from 'react'; import { Box, - Pagination, + Button, Stack, Table, TableBody, @@ -15,44 +15,46 @@ import { createColumnHelper, flexRender, getCoreRowModel, - getFilteredRowModel, - getPaginationRowModel, useReactTable, } from '@tanstack/react-table'; import { useIntl } from 'react-intl'; -import type { ColumnFilter, ColumnFiltersState } from '@tanstack/react-table'; +import type { HistoryTableQuery } from '../queries.generated'; +import usePagination from '@mui/material/usePagination/usePagination'; +import { HistoryFilterButton } from './HistoryButton'; -type Filter = 'swap' | 'yield' | 'received' | 'sent'; - -export interface HistoryRow { - date: Date; - type: Filter; - change: number; - balance: number; - link: string; -} +export type Rows = HistoryTableQuery['addressById']['history']; interface Props { - rows: HistoryRow[]; + rows: Rows; isLoading: boolean; - filter: ColumnFilter; + hasPreviousPage: boolean; + hasNextPage: boolean; + page: number; + setPage: (page: number) => void; } -const columnHelper = createColumnHelper(); +const columnHelper = createColumnHelper(); -export function HistoryTable({ rows, filter }: Props) { +export function HistoryTable({ + rows, + hasNextPage, + hasPreviousPage, + page, + setPage, +}: Props) { const intl = useIntl(); - const [columnFilters, setColumnFilters] = useState([]); const columns = useMemo( () => [ - columnHelper.accessor('date', { - cell: (info) => intl.formatDate(info.getValue()), - header: intl.formatMessage({ defaultMessage: 'Date' }), - }), columnHelper.accessor('type', { - id: 'type', - cell: (info) => info.getValue(), + cell: (info) => ( + <> + {info.getValue()}  + + {intl.formatDate(new Date(info.row.original.timestamp))} + + + ), header: intl.formatMessage({ defaultMessage: 'Type' }), enableColumnFilter: true, filterFn: (row, _, value) => { @@ -60,7 +62,7 @@ export function HistoryTable({ rows, filter }: Props) { return value.value.includes(row.original.type); }, }), - columnHelper.accessor('change', { + columnHelper.accessor('value', { cell: (info) => intl.formatNumber(info.getValue(), quantityFormat), header: intl.formatMessage({ defaultMessage: 'Change' }), }), @@ -69,7 +71,8 @@ export function HistoryTable({ rows, filter }: Props) { - + ), - header: intl.formatMessage({ defaultMessage: 'OETH Balance' }), + header: intl.formatMessage({ defaultMessage: 'Balance' }), }), ], [intl], @@ -101,30 +107,34 @@ export function HistoryTable({ rows, filter }: Props) { pageSize: 20, pageIndex: 0, }, - columnFilters, }, getCoreRowModel: getCoreRowModel(), - getPaginationRowModel: getPaginationRowModel(), - getFilteredRowModel: getFilteredRowModel(), - onColumnFiltersChange: setColumnFilters, + // getPaginationRowModel: getPaginationRowModel(), // add when we do server side pagination // manualPagination: true, - pageCount: rows.length / 3, // add when we do server side pagination // onPaginationChange: setPagination }); - useEffect(() => { - table.getColumn('type')?.setFilterValue(filter); - }, [filter, table]); return ( {table.getHeaderGroups().map((headerGroup) => ( - - {headerGroup.headers.map((header) => ( - + *:first-of-type': { + width: '50%', + }, + }} + > + {headerGroup.headers.map((header, index) => ( + 0 ? 'center' : 'left'} + > {flexRender( header.column.columnDef.header, header.getContext(), @@ -136,10 +146,18 @@ export function HistoryTable({ rows, filter }: Props) { {table.getRowModel().rows.map((row) => ( - + *:first-of-type': { + width: '50%', + }, + }} + > {row.getVisibleCells().map((cell) => (
- table.setPageIndex(page)} - /> + + setPage(page - 1)} + > + {intl.formatMessage({ defaultMessage: 'Previous' })} + + setPage(page + 1)} + > + {intl.formatMessage({ defaultMessage: 'Next' })} + +
); } diff --git a/libs/oeth/history/src/queries.generated.tsx b/libs/oeth/history/src/queries.generated.tsx index c1f9f1a03..235181e51 100644 --- a/libs/oeth/history/src/queries.generated.tsx +++ b/libs/oeth/history/src/queries.generated.tsx @@ -1,28 +1,128 @@ +import * as Types from '@origin/oeth/shared'; + +import { useQuery, UseQueryOptions } from '@tanstack/react-query'; import { graphqlClient } from '@origin/oeth/shared'; -import { useQuery } from '@tanstack/react-query'; +export type HistoryTableQueryVariables = Types.Exact<{ + addressId: Types.Scalars['String']['input']; + offset: Types.Scalars['Int']['input']; +}>; -import type * as Types from '@origin/oeth/shared'; -import type { UseQueryOptions } from '@tanstack/react-query'; -export type DummyQueryVariables = Types.Exact<{ [key: string]: never }>; +export type HistoryTableQuery = { + __typename?: 'Query'; + addressById?: { + __typename?: 'Address'; + balance: number; + earned: number; + isContract: boolean; + rebasingOption: string; + lastUpdated: any; + history: Array<{ + __typename?: 'History'; + type: string; + value: number; + txHash: string; + timestamp: any; + balance: number; + }>; + } | null; +}; -export type DummyQuery = { +export type HistoryTableWithFiltersQueryVariables = Types.Exact<{ + addressId: Types.Scalars['String']['input']; + offset: Types.Scalars['Int']['input']; + filters?: Types.InputMaybe< + Array | Types.Scalars['String']['input'] + >; +}>; + +export type HistoryTableWithFiltersQuery = { __typename?: 'Query'; - squidStatus?: { __typename?: 'SquidStatus'; height?: number | null } | null; + addressById?: { + __typename?: 'Address'; + balance: number; + earned: number; + isContract: boolean; + rebasingOption: string; + lastUpdated: any; + history: Array<{ + __typename?: 'History'; + type: string; + value: number; + txHash: string; + timestamp: any; + balance: number; + }>; + } | null; }; -export const DummyDocument = ` - query Dummy { - squidStatus { - height +export const HistoryTableDocument = ` + query HistoryTable($addressId: String!, $offset: Int!) { + addressById(id: $addressId) { + balance + earned + isContract + rebasingOption + lastUpdated + history(limit: 20, orderBy: timestamp_DESC, offset: $offset) { + type + value + txHash + timestamp + balance + } + } +} + `; +export const useHistoryTableQuery = < + TData = HistoryTableQuery, + TError = unknown, +>( + variables: HistoryTableQueryVariables, + options?: UseQueryOptions, +) => + useQuery( + ['HistoryTable', variables], + graphqlClient( + HistoryTableDocument, + variables, + ), + options, + ); +export const HistoryTableWithFiltersDocument = ` + query HistoryTableWithFilters($addressId: String!, $offset: Int!, $filters: [String!]) { + addressById(id: $addressId) { + balance + earned + isContract + rebasingOption + lastUpdated + history( + limit: 20 + orderBy: timestamp_DESC + offset: $offset + where: {type_in: $filters} + ) { + type + value + txHash + timestamp + balance + } } } `; -export const useDummyQuery = ( - variables?: DummyQueryVariables, - options?: UseQueryOptions, +export const useHistoryTableWithFiltersQuery = < + TData = HistoryTableWithFiltersQuery, + TError = unknown, +>( + variables: HistoryTableWithFiltersQueryVariables, + options?: UseQueryOptions, ) => - useQuery( - variables === undefined ? ['Dummy'] : ['Dummy', variables], - graphqlClient(DummyDocument, variables), + useQuery( + ['HistoryTableWithFilters', variables], + graphqlClient< + HistoryTableWithFiltersQuery, + HistoryTableWithFiltersQueryVariables + >(HistoryTableWithFiltersDocument, variables), options, ); diff --git a/libs/oeth/history/src/queries.graphql b/libs/oeth/history/src/queries.graphql index 6b3cf5a0e..676841d7e 100644 --- a/libs/oeth/history/src/queries.graphql +++ b/libs/oeth/history/src/queries.graphql @@ -1,5 +1,42 @@ -query Dummy { - squidStatus { - height +query HistoryTable($addressId: String!, $offset: Int!) { + addressById(id: $addressId) { + balance + earned + isContract + rebasingOption + lastUpdated + history(limit: 20, orderBy: timestamp_DESC, offset: $offset) { + type + value + txHash + timestamp + balance + } + } +} + +query HistoryTableWithFilters( + $addressId: String! + $offset: Int! + $filters: [String!] +) { + addressById(id: $addressId) { + balance + earned + isContract + rebasingOption + lastUpdated + history( + limit: 20 + orderBy: timestamp_DESC + offset: $offset + where: { type_in: $filters } + ) { + type + value + txHash + timestamp + balance + } } } diff --git a/libs/oeth/history/src/views/HistoryView.tsx b/libs/oeth/history/src/views/HistoryView.tsx index f02d6a0c7..fe0e844e6 100644 --- a/libs/oeth/history/src/views/HistoryView.tsx +++ b/libs/oeth/history/src/views/HistoryView.tsx @@ -1,10 +1,11 @@ import { HistoryCard } from '../components/HistoryCard'; -import { useDummyQuery } from '../queries.generated'; +import { APYContainer } from '../components/APYContainer'; export function HistoryView() { - const { data } = useDummyQuery(); - - console.log(data); - - return ; + return ( + <> + + + + ); } diff --git a/libs/oeth/history/tsconfig.lib.json b/libs/oeth/history/tsconfig.lib.json index 78f9e0f1c..1a2843d1e 100644 --- a/libs/oeth/history/tsconfig.lib.json +++ b/libs/oeth/history/tsconfig.lib.json @@ -20,5 +20,11 @@ "src/**/*.spec.jsx", "src/**/*.test.jsx" ], - "include": ["src/**/*.js", "src/**/*.jsx", "src/**/*.ts", "src/**/*.tsx"] + "include": [ + "src/**/*.js", + "src/**/*.jsx", + "src/**/*.ts", + "src/**/*.tsx", + "src/components/Filters.tsx" + ] } diff --git a/libs/oeth/shared/src/generated/graphql.ts b/libs/oeth/shared/src/generated/graphql.ts index a457de38e..6dfa0d6a2 100644 --- a/libs/oeth/shared/src/generated/graphql.ts +++ b/libs/oeth/shared/src/generated/graphql.ts @@ -38,25 +38,45 @@ export type ApyEdge = { export enum ApyOrderByInput { AprAsc = 'apr_ASC', + AprAscNullsFirst = 'apr_ASC_NULLS_FIRST', AprDesc = 'apr_DESC', + AprDescNullsLast = 'apr_DESC_NULLS_LAST', Apy7DayAvgAsc = 'apy7DayAvg_ASC', + Apy7DayAvgAscNullsFirst = 'apy7DayAvg_ASC_NULLS_FIRST', Apy7DayAvgDesc = 'apy7DayAvg_DESC', + Apy7DayAvgDescNullsLast = 'apy7DayAvg_DESC_NULLS_LAST', Apy14DayAvgAsc = 'apy14DayAvg_ASC', + Apy14DayAvgAscNullsFirst = 'apy14DayAvg_ASC_NULLS_FIRST', Apy14DayAvgDesc = 'apy14DayAvg_DESC', + Apy14DayAvgDescNullsLast = 'apy14DayAvg_DESC_NULLS_LAST', Apy30DayAvgAsc = 'apy30DayAvg_ASC', + Apy30DayAvgAscNullsFirst = 'apy30DayAvg_ASC_NULLS_FIRST', Apy30DayAvgDesc = 'apy30DayAvg_DESC', + Apy30DayAvgDescNullsLast = 'apy30DayAvg_DESC_NULLS_LAST', ApyAsc = 'apy_ASC', + ApyAscNullsFirst = 'apy_ASC_NULLS_FIRST', ApyDesc = 'apy_DESC', + ApyDescNullsLast = 'apy_DESC_NULLS_LAST', BlockNumberAsc = 'blockNumber_ASC', + BlockNumberAscNullsFirst = 'blockNumber_ASC_NULLS_FIRST', BlockNumberDesc = 'blockNumber_DESC', + BlockNumberDescNullsLast = 'blockNumber_DESC_NULLS_LAST', IdAsc = 'id_ASC', + IdAscNullsFirst = 'id_ASC_NULLS_FIRST', IdDesc = 'id_DESC', + IdDescNullsLast = 'id_DESC_NULLS_LAST', RebasingCreditsPerTokenAsc = 'rebasingCreditsPerToken_ASC', + RebasingCreditsPerTokenAscNullsFirst = 'rebasingCreditsPerToken_ASC_NULLS_FIRST', RebasingCreditsPerTokenDesc = 'rebasingCreditsPerToken_DESC', + RebasingCreditsPerTokenDescNullsLast = 'rebasingCreditsPerToken_DESC_NULLS_LAST', TimestampAsc = 'timestamp_ASC', + TimestampAscNullsFirst = 'timestamp_ASC_NULLS_FIRST', TimestampDesc = 'timestamp_DESC', + TimestampDescNullsLast = 'timestamp_DESC_NULLS_LAST', TxHashAsc = 'txHash_ASC', - TxHashDesc = 'txHash_DESC' + TxHashAscNullsFirst = 'txHash_ASC_NULLS_FIRST', + TxHashDesc = 'txHash_DESC', + TxHashDescNullsLast = 'txHash_DESC_NULLS_LAST' } export type ApyWhereInput = { @@ -205,19 +225,33 @@ export type AddressEdge = { export enum AddressOrderByInput { BalanceAsc = 'balance_ASC', + BalanceAscNullsFirst = 'balance_ASC_NULLS_FIRST', BalanceDesc = 'balance_DESC', + BalanceDescNullsLast = 'balance_DESC_NULLS_LAST', CreditsAsc = 'credits_ASC', + CreditsAscNullsFirst = 'credits_ASC_NULLS_FIRST', CreditsDesc = 'credits_DESC', + CreditsDescNullsLast = 'credits_DESC_NULLS_LAST', EarnedAsc = 'earned_ASC', + EarnedAscNullsFirst = 'earned_ASC_NULLS_FIRST', EarnedDesc = 'earned_DESC', + EarnedDescNullsLast = 'earned_DESC_NULLS_LAST', IdAsc = 'id_ASC', + IdAscNullsFirst = 'id_ASC_NULLS_FIRST', IdDesc = 'id_DESC', + IdDescNullsLast = 'id_DESC_NULLS_LAST', IsContractAsc = 'isContract_ASC', + IsContractAscNullsFirst = 'isContract_ASC_NULLS_FIRST', IsContractDesc = 'isContract_DESC', + IsContractDescNullsLast = 'isContract_DESC_NULLS_LAST', LastUpdatedAsc = 'lastUpdated_ASC', + LastUpdatedAscNullsFirst = 'lastUpdated_ASC_NULLS_FIRST', LastUpdatedDesc = 'lastUpdated_DESC', + LastUpdatedDescNullsLast = 'lastUpdated_DESC_NULLS_LAST', RebasingOptionAsc = 'rebasingOption_ASC', - RebasingOptionDesc = 'rebasingOption_DESC' + RebasingOptionAscNullsFirst = 'rebasingOption_ASC_NULLS_FIRST', + RebasingOptionDesc = 'rebasingOption_DESC', + RebasingOptionDescNullsLast = 'rebasingOption_DESC_NULLS_LAST' } export type AddressWhereInput = { @@ -335,33 +369,61 @@ export type HistoryEdge = { export enum HistoryOrderByInput { AddressBalanceAsc = 'address_balance_ASC', + AddressBalanceAscNullsFirst = 'address_balance_ASC_NULLS_FIRST', AddressBalanceDesc = 'address_balance_DESC', + AddressBalanceDescNullsLast = 'address_balance_DESC_NULLS_LAST', AddressCreditsAsc = 'address_credits_ASC', + AddressCreditsAscNullsFirst = 'address_credits_ASC_NULLS_FIRST', AddressCreditsDesc = 'address_credits_DESC', + AddressCreditsDescNullsLast = 'address_credits_DESC_NULLS_LAST', AddressEarnedAsc = 'address_earned_ASC', + AddressEarnedAscNullsFirst = 'address_earned_ASC_NULLS_FIRST', AddressEarnedDesc = 'address_earned_DESC', + AddressEarnedDescNullsLast = 'address_earned_DESC_NULLS_LAST', AddressIdAsc = 'address_id_ASC', + AddressIdAscNullsFirst = 'address_id_ASC_NULLS_FIRST', AddressIdDesc = 'address_id_DESC', + AddressIdDescNullsLast = 'address_id_DESC_NULLS_LAST', AddressIsContractAsc = 'address_isContract_ASC', + AddressIsContractAscNullsFirst = 'address_isContract_ASC_NULLS_FIRST', AddressIsContractDesc = 'address_isContract_DESC', + AddressIsContractDescNullsLast = 'address_isContract_DESC_NULLS_LAST', AddressLastUpdatedAsc = 'address_lastUpdated_ASC', + AddressLastUpdatedAscNullsFirst = 'address_lastUpdated_ASC_NULLS_FIRST', AddressLastUpdatedDesc = 'address_lastUpdated_DESC', + AddressLastUpdatedDescNullsLast = 'address_lastUpdated_DESC_NULLS_LAST', AddressRebasingOptionAsc = 'address_rebasingOption_ASC', + AddressRebasingOptionAscNullsFirst = 'address_rebasingOption_ASC_NULLS_FIRST', AddressRebasingOptionDesc = 'address_rebasingOption_DESC', + AddressRebasingOptionDescNullsLast = 'address_rebasingOption_DESC_NULLS_LAST', BalanceAsc = 'balance_ASC', + BalanceAscNullsFirst = 'balance_ASC_NULLS_FIRST', BalanceDesc = 'balance_DESC', + BalanceDescNullsLast = 'balance_DESC_NULLS_LAST', BlockNumberAsc = 'blockNumber_ASC', + BlockNumberAscNullsFirst = 'blockNumber_ASC_NULLS_FIRST', BlockNumberDesc = 'blockNumber_DESC', + BlockNumberDescNullsLast = 'blockNumber_DESC_NULLS_LAST', IdAsc = 'id_ASC', + IdAscNullsFirst = 'id_ASC_NULLS_FIRST', IdDesc = 'id_DESC', + IdDescNullsLast = 'id_DESC_NULLS_LAST', TimestampAsc = 'timestamp_ASC', + TimestampAscNullsFirst = 'timestamp_ASC_NULLS_FIRST', TimestampDesc = 'timestamp_DESC', + TimestampDescNullsLast = 'timestamp_DESC_NULLS_LAST', TxHashAsc = 'txHash_ASC', + TxHashAscNullsFirst = 'txHash_ASC_NULLS_FIRST', TxHashDesc = 'txHash_DESC', + TxHashDescNullsLast = 'txHash_DESC_NULLS_LAST', TypeAsc = 'type_ASC', + TypeAscNullsFirst = 'type_ASC_NULLS_FIRST', TypeDesc = 'type_DESC', + TypeDescNullsLast = 'type_DESC_NULLS_LAST', ValueAsc = 'value_ASC', - ValueDesc = 'value_DESC' + ValueAscNullsFirst = 'value_ASC_NULLS_FIRST', + ValueDesc = 'value_DESC', + ValueDescNullsLast = 'value_DESC_NULLS_LAST' } export type HistoryWhereInput = { @@ -615,39 +677,73 @@ export type RebaseEdge = { export enum RebaseOrderByInput { ApyAprAsc = 'apy_apr_ASC', + ApyAprAscNullsFirst = 'apy_apr_ASC_NULLS_FIRST', ApyAprDesc = 'apy_apr_DESC', + ApyAprDescNullsLast = 'apy_apr_DESC_NULLS_LAST', ApyApy7DayAvgAsc = 'apy_apy7DayAvg_ASC', + ApyApy7DayAvgAscNullsFirst = 'apy_apy7DayAvg_ASC_NULLS_FIRST', ApyApy7DayAvgDesc = 'apy_apy7DayAvg_DESC', + ApyApy7DayAvgDescNullsLast = 'apy_apy7DayAvg_DESC_NULLS_LAST', ApyApy14DayAvgAsc = 'apy_apy14DayAvg_ASC', + ApyApy14DayAvgAscNullsFirst = 'apy_apy14DayAvg_ASC_NULLS_FIRST', ApyApy14DayAvgDesc = 'apy_apy14DayAvg_DESC', + ApyApy14DayAvgDescNullsLast = 'apy_apy14DayAvg_DESC_NULLS_LAST', ApyApy30DayAvgAsc = 'apy_apy30DayAvg_ASC', + ApyApy30DayAvgAscNullsFirst = 'apy_apy30DayAvg_ASC_NULLS_FIRST', ApyApy30DayAvgDesc = 'apy_apy30DayAvg_DESC', + ApyApy30DayAvgDescNullsLast = 'apy_apy30DayAvg_DESC_NULLS_LAST', ApyApyAsc = 'apy_apy_ASC', + ApyApyAscNullsFirst = 'apy_apy_ASC_NULLS_FIRST', ApyApyDesc = 'apy_apy_DESC', + ApyApyDescNullsLast = 'apy_apy_DESC_NULLS_LAST', ApyBlockNumberAsc = 'apy_blockNumber_ASC', + ApyBlockNumberAscNullsFirst = 'apy_blockNumber_ASC_NULLS_FIRST', ApyBlockNumberDesc = 'apy_blockNumber_DESC', + ApyBlockNumberDescNullsLast = 'apy_blockNumber_DESC_NULLS_LAST', ApyIdAsc = 'apy_id_ASC', + ApyIdAscNullsFirst = 'apy_id_ASC_NULLS_FIRST', ApyIdDesc = 'apy_id_DESC', + ApyIdDescNullsLast = 'apy_id_DESC_NULLS_LAST', ApyRebasingCreditsPerTokenAsc = 'apy_rebasingCreditsPerToken_ASC', + ApyRebasingCreditsPerTokenAscNullsFirst = 'apy_rebasingCreditsPerToken_ASC_NULLS_FIRST', ApyRebasingCreditsPerTokenDesc = 'apy_rebasingCreditsPerToken_DESC', + ApyRebasingCreditsPerTokenDescNullsLast = 'apy_rebasingCreditsPerToken_DESC_NULLS_LAST', ApyTimestampAsc = 'apy_timestamp_ASC', + ApyTimestampAscNullsFirst = 'apy_timestamp_ASC_NULLS_FIRST', ApyTimestampDesc = 'apy_timestamp_DESC', + ApyTimestampDescNullsLast = 'apy_timestamp_DESC_NULLS_LAST', ApyTxHashAsc = 'apy_txHash_ASC', + ApyTxHashAscNullsFirst = 'apy_txHash_ASC_NULLS_FIRST', ApyTxHashDesc = 'apy_txHash_DESC', + ApyTxHashDescNullsLast = 'apy_txHash_DESC_NULLS_LAST', BlockNumberAsc = 'blockNumber_ASC', + BlockNumberAscNullsFirst = 'blockNumber_ASC_NULLS_FIRST', BlockNumberDesc = 'blockNumber_DESC', + BlockNumberDescNullsLast = 'blockNumber_DESC_NULLS_LAST', IdAsc = 'id_ASC', + IdAscNullsFirst = 'id_ASC_NULLS_FIRST', IdDesc = 'id_DESC', + IdDescNullsLast = 'id_DESC_NULLS_LAST', RebasingCreditsPerTokenAsc = 'rebasingCreditsPerToken_ASC', + RebasingCreditsPerTokenAscNullsFirst = 'rebasingCreditsPerToken_ASC_NULLS_FIRST', RebasingCreditsPerTokenDesc = 'rebasingCreditsPerToken_DESC', + RebasingCreditsPerTokenDescNullsLast = 'rebasingCreditsPerToken_DESC_NULLS_LAST', RebasingCreditsAsc = 'rebasingCredits_ASC', + RebasingCreditsAscNullsFirst = 'rebasingCredits_ASC_NULLS_FIRST', RebasingCreditsDesc = 'rebasingCredits_DESC', + RebasingCreditsDescNullsLast = 'rebasingCredits_DESC_NULLS_LAST', TimestampAsc = 'timestamp_ASC', + TimestampAscNullsFirst = 'timestamp_ASC_NULLS_FIRST', TimestampDesc = 'timestamp_DESC', + TimestampDescNullsLast = 'timestamp_DESC_NULLS_LAST', TotalSupplyAsc = 'totalSupply_ASC', + TotalSupplyAscNullsFirst = 'totalSupply_ASC_NULLS_FIRST', TotalSupplyDesc = 'totalSupply_DESC', + TotalSupplyDescNullsLast = 'totalSupply_DESC_NULLS_LAST', TxHashAsc = 'txHash_ASC', - TxHashDesc = 'txHash_DESC' + TxHashAscNullsFirst = 'txHash_ASC_NULLS_FIRST', + TxHashDesc = 'txHash_DESC', + TxHashDescNullsLast = 'txHash_DESC_NULLS_LAST' } export type RebaseWhereInput = { diff --git a/libs/oeth/swap/src/components/GasPopover.tsx b/libs/oeth/swap/src/components/GasPopover.tsx index 3fa336c44..3f477a105 100644 --- a/libs/oeth/swap/src/components/GasPopover.tsx +++ b/libs/oeth/swap/src/components/GasPopover.tsx @@ -89,7 +89,7 @@ export function GasPopover({ buttonProps }: Props) { }, }} > - + {intl.formatMessage({ defaultMessage: 'Slippage' })} @@ -100,8 +100,9 @@ export function GasPopover({ buttonProps }: Props) { value={slippage} fullWidth sx={{ - borderColor: 'var(--origin-blue)', - backgroundColor: alpha('#0074F0', 0.05), + borderColor: (theme) => theme.palette.secondary.main, + backgroundColor: (theme) => + alpha(theme.palette.secondary.main, 0.05), paddingInlineEnd: 2, '& .MuiInputBase-input': { textAlign: 'right', @@ -180,12 +181,13 @@ export function GasPopover({ buttonProps }: Props) { )} fullWidth sx={{ - borderColor: 'var(--origin-blue)', - backgroundColor: alpha('#0074F0', 0.05), + borderColor: (theme) => theme.palette.secondary.main, + backgroundColor: (theme) => + alpha(theme.palette.secondary.main, 0.05), paddingInlineEnd: 2, '& .MuiInputBase-input': { textAlign: 'right', - borderColor: 'var(--origin-blue)', + borderColor: (theme) => theme.palette.secondary.main, color: 'primary.contrastText', '&::placeholder': { color: 'text.primary', diff --git a/libs/oeth/swap/src/views/SwapView.tsx b/libs/oeth/swap/src/views/SwapView.tsx index 1094945b7..b0bf0c3eb 100644 --- a/libs/oeth/swap/src/views/SwapView.tsx +++ b/libs/oeth/swap/src/views/SwapView.tsx @@ -23,6 +23,7 @@ import type { IconButtonProps, Theme } from '@mui/material'; import type { Token } from '@origin/shared/contracts'; import type { TokenSource } from '../types'; +import { ApyHeader } from '@origin/oeth/shared'; const commonStyles = { paddingBlock: 2.5, @@ -81,7 +82,9 @@ function SwapViewWrapped() { return ( <> + + + + + + diff --git a/libs/shared/components/src/Checkbox/CheckboxIcon.tsx b/libs/shared/components/src/Checkbox/CheckboxIcon.tsx new file mode 100644 index 000000000..cca54342b --- /dev/null +++ b/libs/shared/components/src/Checkbox/CheckboxIcon.tsx @@ -0,0 +1,42 @@ +import { SvgIcon } from '@mui/material'; + +export function CheckboxIcon() { + return ( + + + + + + + + + + + + + + + ); +} diff --git a/libs/shared/components/src/Checkbox/EmptyCheckbox.tsx b/libs/shared/components/src/Checkbox/EmptyCheckbox.tsx new file mode 100644 index 000000000..cda8a1c08 --- /dev/null +++ b/libs/shared/components/src/Checkbox/EmptyCheckbox.tsx @@ -0,0 +1,25 @@ +import { SvgIcon } from '@mui/material'; +import React from 'react'; + +export function EmptyCheckbox() { + return ( + + + + + + ); +} diff --git a/libs/shared/components/src/Checkbox/index.tsx b/libs/shared/components/src/Checkbox/index.tsx new file mode 100644 index 000000000..b4fc50636 --- /dev/null +++ b/libs/shared/components/src/Checkbox/index.tsx @@ -0,0 +1,2 @@ +export * from './CheckboxIcon'; +export * from './EmptyCheckbox'; diff --git a/libs/shared/components/src/LinkIcon/index.tsx b/libs/shared/components/src/LinkIcon/index.tsx index ba3ff18df..a38d940ba 100644 --- a/libs/shared/components/src/LinkIcon/index.tsx +++ b/libs/shared/components/src/LinkIcon/index.tsx @@ -1,13 +1,16 @@ import { Box, Link } from '@mui/material'; +import type { SxProps } from '@mui/material'; + interface Props { url: string; size?: string; + sx?: SxProps; } -export function LinkIcon({ url, size = '0.875rem' }: Props) { +export function LinkIcon({ url, size = '0.875rem', sx }: Props) { return ( - + ({ - paddingInline: theme.spacing(5), - paddingBlock: theme.spacing(3), + paddingInline: { xs: theme.spacing(2), md: theme.spacing(3) }, + paddingBlock: theme.spacing(2), color: theme.palette.primary.contrastText, + fontSize: theme.typography.pxToRem(14), + fontStyle: 'normal', + fontWeight: 400, + lineHeight: theme.typography.pxToRem(23), }), head: ({ theme }) => ({ color: theme.palette.text.secondary,