Skip to content

Commit

Permalink
Merge pull request #42 from OriginProtocol/feat/redeem-page
Browse files Browse the repository at this point in the history
[TAS-270] Feat/redeem page
  • Loading branch information
rafaelugolini authored Sep 18, 2023
2 parents 45db8cc + 291445d commit 7b6870d
Show file tree
Hide file tree
Showing 44 changed files with 1,411 additions and 673 deletions.
6 changes: 6 additions & 0 deletions apps/oeth/src/routes.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { HistoryView } from '@origin/oeth/history';
import { RedeemView } from '@origin/oeth/redeem';
import { SwapView } from '@origin/oeth/swap';
import { defineMessage } from 'react-intl';

Expand All @@ -16,6 +17,11 @@ export const routes: RouteObject[] = [
Component: SwapView,
handle: { label: defineMessage({ defaultMessage: 'Swap' }) },
},
{
path: '/redeem',
Component: RedeemView,
handle: { label: defineMessage({ defaultMessage: 'Redeem' }) },
},
{
path: '/history',
Component: HistoryView,
Expand Down
12 changes: 12 additions & 0 deletions libs/oeth/redeem/.babelrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"presets": [
[
"@nx/react/babel",
{
"runtime": "automatic",
"useBuiltIns": "usage"
}
]
],
"plugins": []
}
34 changes: 34 additions & 0 deletions libs/oeth/redeem/.eslintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
{
"extends": [
"plugin:@nx/react",
"../../../.eslintrc.json"
],
"ignorePatterns": [
"!**/*"
],
"overrides": [
{
"files": [
"*.ts",
"*.tsx",
"*.js",
"*.jsx"
],
"rules": {}
},
{
"files": [
"*.ts",
"*.tsx"
],
"rules": {}
},
{
"files": [
"*.js",
"*.jsx"
],
"rules": {}
}
]
}
7 changes: 7 additions & 0 deletions libs/oeth/redeem/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# redeem

This library was generated with [Nx](https://nx.dev).

## Running unit tests

Run `nx test redeem` to execute the unit tests via [Jest](https://jestjs.io).
20 changes: 20 additions & 0 deletions libs/oeth/redeem/project.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"name": "oeth-redeem",
"$schema": "../../../node_modules/nx/schemas/project-schema.json",
"sourceRoot": "libs/oeth/redeem/src",
"projectType": "library",
"tags": [],
"targets": {
"lint": {
"executor": "@nx/linter:eslint",
"outputs": [
"{options.outputFile}"
],
"options": {
"lintFilePatterns": [
"libs/oeth/redeem/**/*.{ts,tsx,js,jsx}"
]
}
}
}
}
43 changes: 43 additions & 0 deletions libs/oeth/redeem/src/components/Mix.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { Box, Stack } from '@mui/material';

import type { SxProps } from '@mui/material';

interface Props {
size?: number;
sx?: SxProps;
}

export function Mix({ size = 2, sx }: Props) {
const imgSrc = [
'/images/currency/weth-icon-small.png',
'/images/currency/reth-icon-small.png',
'/images/currency/steth-icon-small.svg',
'/images/currency/frxeth-icon-small.svg',
];

return (
<Stack
direction="row"
sx={{
width: `calc(${imgSrc.length * size}rem - ${
(size / 2.66666) * (imgSrc.length - 1)
}rem)`,
...sx,
}}
>
{imgSrc.map((img, index, arr) => (
<Box
key={img}
sx={{
height: `${size}rem`,
width: `${size}rem`,
zIndex: arr.length - index,
transform: `translateX(-${(index * size) / 2.66666}rem)`,
}}
src={img}
component="img"
/>
))}
</Stack>
);
}
43 changes: 43 additions & 0 deletions libs/oeth/redeem/src/components/RedeemInfo.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { Box, Tooltip, Typography } from '@mui/material';
import { useIntl } from 'react-intl';

import type { Theme } from '@mui/material';

export function RedeemInfo() {
const intl = useIntl();

return (
<Tooltip
title={
<Typography color="text.secondary" variant="body2">
{intl.formatMessage({
defaultMessage: 'Redeem OETH for the basket of underlying assets',
})}
</Typography>
}
componentsProps={{
tooltip: {
sx: {
paddingInline: 2,
paddingBlock: 1.5,
borderRadius: 2,
border: '1px solid',
borderColor: (theme) => theme.palette.grey[500],
boxShadow: (theme: Theme) => theme.shadows[23],
},
},
}}
>
<Box
component="img"
src="/images/info.svg"
data-testid="swap-route-info"
sx={{
width: (theme) => theme.typography.pxToRem(12),
height: (theme) => theme.typography.pxToRem(12),
color: (theme) => theme.palette.text.secondary,
}}
></Box>
</Tooltip>
);
}
61 changes: 61 additions & 0 deletions libs/oeth/redeem/src/components/RedeemRoute.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import { Collapse, Stack, Typography } from '@mui/material';
import { Card, cardStyles } from '@origin/shared/components';
import { useIntl } from 'react-intl';

import { useRedeemState } from '../state';
import { RedeemInfo } from './RedeemInfo';
import { RedeemSplitCard } from './RedeemSplitCard';
import { RouteCard } from './RouteCard';

import type { CardProps } from '@mui/material';

export function RedeemRoute(props: Omit<CardProps, 'children'>) {
const intl = useIntl();
const [{ amountOut }] = useRedeemState();

const hasContent = amountOut > 0n;

return (
<Card
{...props}
sx={{
border: '1px solid',
borderColor: (theme) => theme.palette.background.default,
backgroundColor: 'grey.900',
borderRadius: 1,
...props?.sx,
}}
title={
<Stack
direction="row"
gap={0.5}
component={Typography}
variant="body2"
alignItems="center"
color="primary.contrastText"
>
{intl.formatMessage({ defaultMessage: 'Route' })}
<RedeemInfo />
</Stack>
}
sxCardTitle={{ borderBottom: 'none', paddingBlock: 1, paddingInline: 2 }}
sxCardContent={{
...(hasContent
? cardStyles
: {
p: 0,
paddingBlock: 0,
paddingInline: 0,
'&:last-child': { pb: 0 },
}),
}}
>
<Collapse in={hasContent}>
<Stack spacing={1}>
<RouteCard />
<RedeemSplitCard />
</Stack>
</Collapse>
</Card>
);
}
96 changes: 96 additions & 0 deletions libs/oeth/redeem/src/components/RedeemSplitCard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
import {
Box,
Card,
CardHeader,
Skeleton,
Stack,
Typography,
} from '@mui/material';
import { usePrices } from '@origin/shared/providers';
import { currencyFormat, formatAmount } from '@origin/shared/utils';
import { useIntl } from 'react-intl';
import { formatUnits } from 'viem';

import { useRedeemState } from '../state';
import { Mix } from './Mix';

import type { CardProps } from '@origin/shared/components';

export const RedeemSplitCard = (
props: Omit<CardProps, 'children' | 'title'>,
) => {
const intl = useIntl();
const { data: prices, isLoading: isPricesLoading } = usePrices();
const [{ split, isEstimateLoading }] = useRedeemState();

return (
<Card
{...props}
sx={{
padding: 1.5,
boxShadow: 'none',
borderRadius: 1,
height: 1,
...props?.sx,
}}
>
<CardHeader
sx={{
padding: (theme) => theme.spacing(0.5, 0, 1.5, 0),
borderBottom: (theme) => `1px solid ${theme.palette.divider}`,
}}
title={
<Stack direction="row" alignItems="center" spacing={1}>
<Mix />
<Typography>
{intl.formatMessage({
defaultMessage: 'Redeem basket of assets',
})}
</Typography>
</Stack>
}
/>
<Stack spacing={1} pt={3}>
{split?.map((s) => {
const converted =
+formatUnits(s.amount, s.token.decimals) * prices?.[s.token.symbol];

return (
<Stack
key={s.token.symbol}
direction="row"
justifyContent="space-between"
alignItems="center"
>
<Stack direction="row" alignItems="center" spacing={1}>
<Box component="img" src={s.token.icon} />
<Typography>{s.token.symbol}</Typography>
</Stack>
<Stack
direction="row"
alignItems="center"
justifyContent="flex-end"
spacing={2}
>
<Typography color="primary.contrastText">
{isEstimateLoading ? (
<Skeleton width={80} />
) : (
formatAmount(s.amount, s.token.decimals)
)}
</Typography>
{isPricesLoading || isEstimateLoading ? (
<Skeleton width={80} />
) : (
<Typography sx={{ minWidth: 100, textAlign: 'end' }}>
{intl.formatNumber(converted, currencyFormat)}
</Typography>
)}
</Stack>
</Stack>
);
})}
</Stack>
</Card>
);
};
Loading

0 comments on commit 7b6870d

Please sign in to comment.