Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/d3charts' into d3charts
Browse files Browse the repository at this point in the history
  • Loading branch information
pingustar committed Jan 29, 2024
2 parents 61acd51 + 5f7c949 commit df4910a
Show file tree
Hide file tree
Showing 41 changed files with 602 additions and 48 deletions.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 6 additions & 0 deletions src/assets/icons/arrow-round.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 5 additions & 0 deletions src/assets/icons/calendar.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
9 changes: 9 additions & 0 deletions src/assets/icons/download.svg
5 changes: 5 additions & 0 deletions src/assets/icons/image.svg
5 changes: 5 additions & 0 deletions src/assets/icons/movie.svg
5 changes: 5 additions & 0 deletions src/assets/icons/page.svg
51 changes: 51 additions & 0 deletions src/components/simulator/SimulatorChartHeader.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { ReactComponent as CalendarIcon } from 'assets/icons/calendar.svg';
import { SimulatorPageTabs } from './SimulatorPageTabs';
import { SimulatorDownloadMenu } from './SimulatorDownload';
import { SimulatorReturn } from 'libs/queries';

interface Props extends Pick<SimulatorReturn, 'data'> {
showSummary: boolean;
setShowSummary: React.Dispatch<React.SetStateAction<boolean>>;
}

export const SimulatorChartHeader = ({
showSummary,
setShowSummary,
data,
}: Props) => {
const startTimestamp = data![0].date * 1e3; // ms
const endTimestamp = data![data.length - 1].date * 1e3; // ms

const dateFormatOptions: Intl.DateTimeFormatOptions = {
year: 'numeric',
month: 'long',
day: '2-digit',
};

const startDate = new Intl.DateTimeFormat('en-US', dateFormatOptions).format(
startTimestamp
);
const endDate = new Intl.DateTimeFormat('en-US', dateFormatOptions).format(
endTimestamp
);

return (
<section className="flex flex-wrap items-center justify-evenly gap-8 py-8 px-24 md:justify-between">
<article className="flex items-center gap-8">
<span className="h-24 w-24 items-center justify-center rounded-[12px] bg-white/10">
<CalendarIcon className="h-12 w-12" />
</span>
<span className="justify-self-end text-14 text-white/80">
{startDate}{endDate}
</span>
</article>
<article className="flex items-center gap-8">
<SimulatorPageTabs
setShowSummary={setShowSummary}
showSummary={showSummary}
/>
<SimulatorDownloadMenu data={data} />
</article>
</section>
);
};
102 changes: 102 additions & 0 deletions src/components/simulator/SimulatorDownload.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
import { cn } from 'utils/helpers';
import { ReactComponent as IconLog } from 'assets/icons/page.svg';
import { ReactComponent as IconAnimation } from 'assets/icons/movie.svg';
import { ReactComponent as IconSummary } from 'assets/icons/image.svg';
import { ReactComponent as IconDownload } from 'assets/icons/download.svg';
import { DropdownMenu } from 'components/common/dropdownMenu';
import { useState } from 'react';
import { buttonStyles } from 'components/common/button/buttonStyles';
import { SimulatorReturn } from 'libs/queries';
import { CsvDataService } from 'libs/csv';

interface Props extends Pick<SimulatorReturn, 'data'> {}

export const SimulatorDownloadMenu = ({ data }: Props) => {
const [isOpen, setIsOpen] = useState(false);

const items = [
{
id: 'summaryView',
title: 'Summary View',
subTitle: 'JPEG',
action: () => console.log('Summary View'),
icon: <IconSummary className="h-20 w-20" />,
},
{
id: 'animation' as const,
title: 'Animation',
subTitle: 'GIF',
action: () => console.log('Animation'),
icon: <IconAnimation className="h-20 w-20" />,
},
{
id: 'simulationLog' as const,
title: 'Simulation Log',
subTitle: 'CSV',
action: () => {
const csvOutput = data.map((item) => {
return {
...item,
date: new Date(item.date * 1e3),
};
});
CsvDataService.exportToCsv('data.csv', csvOutput);
},
icon: <IconLog className="h-20 w-20" />,
},
];

return (
<DropdownMenu
isOpen={isOpen}
setIsOpen={setIsOpen}
placement="bottom-end"
className="rounded-[10px] !border-0 p-8 text-white"
aria-expanded={isOpen}
button={(attr) => (
<button
{...attr}
className={cn(
buttonStyles({ variant: 'black' }),
'relative h-40 w-40 border-silver !p-0'
)}
onClick={(e) => {
setIsOpen(true);
attr.onClick(e);
}}
aria-label="Download Simulation"
>
<span className="flex h-36 w-36 items-center justify-center">
<IconDownload className="h-18 w-18" />
</span>
</button>
)}
>
{items?.map(({ id, action, title, subTitle, icon }, index) => {
return (
<div key={`${index}_${id}`} className="border-grey5">
<button
role="menuitem"
aria-labelledby="optionTitle"
className="hover:bg-body w-full rounded-6 p-8 text-left"
onClick={() => {
action();
setIsOpen(false);
}}
>
<div className="flex items-center gap-y-8">
{icon}
<span id="optionTitle" className="mx-8 text-14 font-weight-500">
{title}
</span>
<span className="text-14 font-weight-400 text-white/40">
{subTitle}
</span>
</div>
</button>
</div>
);
})}
</DropdownMenu>
);
};
58 changes: 58 additions & 0 deletions src/components/simulator/SimulatorPageTabs.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import { Pathnames, PathParams } from 'libs/routing';
import { cn } from 'utils/helpers';
import { ReactComponent as IconAnimation } from 'assets/icons/movie.svg';
import { ReactComponent as IconSummary } from 'assets/icons/image.svg';

export interface StrategyTab {
label: string;
href: Pathnames;
params?: PathParams;
icon: JSX.Element;
badge?: number;
}

interface Props {
showSummary: boolean;
setShowSummary: React.Dispatch<React.SetStateAction<boolean>>;
}

export const SimulatorPageTabs = ({ showSummary, setShowSummary }: Props) => {
const tabs = [
{
label: 'Animation',
icon: <IconAnimation className="h-18 w-18" />,
isActive: () => !showSummary,
click: () => setShowSummary(false),
},
{
label: 'Summary',
icon: <IconSummary className="h-18 w-18" />,
isActive: () => showSummary,
click: () => setShowSummary(true),
},
];

return (
<nav
aria-label="Simulation Tabs"
className="max-w-40 flex h-40 w-full gap-2 rounded-full border-2 border-silver p-4 text-14 md:w-auto"
>
{tabs.map(({ label, icon, isActive, click }) => {
const active = isActive();
return (
<button
key={label}
onClick={click}
className={cn(
'flex w-full items-center justify-center gap-4 rounded-full py-5 px-16',
active ? 'bg-white/10' : 'bg-transparent text-white/60'
)}
>
{icon}
<span className="text-14 font-weight-500">{label}</span>
</button>
);
})}
</nav>
);
};
73 changes: 73 additions & 0 deletions src/components/simulator/SimulatorSummary.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import { Link, useSearch } from 'libs/routing';
import { buttonStyles } from 'components/common/button/buttonStyles';
import { SimulatorSummaryGains } from './SimulatorSummaryGains';
import { SimulatorSummaryRoi } from './SimulatorSummaryRoi';
import { SimulatorSummaryTokens } from './SimulatorTokens';
import { SimulatorSummaryTable } from './SimulatorSummaryTable';
import { useTokens } from 'hooks/useTokens';

interface Props {
roi: number;
gains: number;
isLoading: boolean;
}

export const SimulatorSummary = ({ roi, gains, isLoading }: Props) => {
const search = useSearch({ from: '/simulator/result' });

const portfolioGains = isLoading ? 0.0 : gains;
const portfolioRoi = isLoading ? 0.0 : roi;

const { getTokenById } = useTokens();
const baseToken = getTokenById(search.baseToken);
const quoteToken = getTokenById(search.quoteToken);

const summaryData = {
buyMin: search.buyMin,
buyMax: search.buyMax,
sellMin: search.sellMin,
sellMax: search.sellMax,
baseBudget: search.baseBudget,
quoteBudget: search.quoteBudget,
};

const strategyType = 'recurring';

return (
<header className="my-8 flex flex-wrap gap-8">
<section className="flex flex-grow flex-wrap items-center justify-evenly gap-8 rounded-10 bg-black p-16 md:justify-between">
<SimulatorSummaryTokens
baseToken={baseToken!}
quoteToken={quoteToken!}
strategyType={strategyType}
/>
<SimulatorSummaryTable
summaryData={summaryData}
baseToken={baseToken!}
quoteToken={quoteToken!}
/>
</section>
<section className="flex flex-grow flex-wrap items-center justify-evenly gap-8 rounded-10 bg-black p-16 md:justify-between">
<SimulatorSummaryGains
portfolioGains={portfolioGains}
quoteToken={quoteToken!}
/>
<SimulatorSummaryRoi portfolioRoi={portfolioRoi} />
<Link
to="/strategies/create"
search={{
base: baseToken!.address,
quote: quoteToken!.address,
strategyType:
strategyType === 'recurring' ? 'recurring' : undefined,
strategySettings:
strategyType === 'recurring' ? 'range' : 'overlapping',
}}
className={buttonStyles({ variant: 'success', size: 'md' })}
>
Create strategy
</Link>
</section>
</header>
);
};
39 changes: 39 additions & 0 deletions src/components/simulator/SimulatorSummaryGains.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { Tooltip } from 'components/common/tooltip/Tooltip';
import { ReactComponent as IconTooltip } from 'assets/icons/tooltip.svg';
import { cn, prettifyNumber } from 'utils/helpers';
import { FC } from 'react';
import { Token } from 'libs/tokens';
import { useFiatCurrency } from 'hooks/useFiatCurrency';

interface Props {
quoteToken: Token;
portfolioGains: number;
}

export const SimulatorSummaryGains = ({
portfolioGains,
quoteToken,
}: Props) => {
const quoteFiat = useFiatCurrency(quoteToken);
const budgetFormatted = prettifyNumber(portfolioGains, {
currentCurrency: quoteFiat.selectedFiatCurrency,
});

return (
<article className={cn('flex flex-col rounded-8')}>
<Tooltip element={<TooltipContent />}>
<h4 className="text-secondary flex items-center gap-4 font-mono !text-12">
Estimated Gains
<IconTooltip className="h-10 w-10" />
</h4>
</Tooltip>
<p className={`text-24 font-weight-500`}>{budgetFormatted}</p>
</article>
);
};

const TooltipContent: FC<{}> = () => (
<>
<span className="align-middle">TBD.&nbsp;</span>
</>
);
Loading

0 comments on commit df4910a

Please sign in to comment.