Skip to content

Commit

Permalink
edit with creation flow
Browse files Browse the repository at this point in the history
  • Loading branch information
GrandSchtroumpf committed Jan 17, 2025
1 parent 3f361f0 commit 9855825
Show file tree
Hide file tree
Showing 19 changed files with 713 additions and 100 deletions.
17 changes: 16 additions & 1 deletion src/components/cart/CartStrategy.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { StrategyBlockBudget } from 'components/strategies/overview/strategyBloc
import { StrategyBlockBuySell } from 'components/strategies/overview/strategyBlock/StrategyBlockBuySell';
import { StrategyGraph } from 'components/strategies/overview/strategyBlock/StrategyGraph';
import { ReactComponent as IconTrash } from 'assets/icons/trash.svg';
import { ReactComponent as IconEdit } from 'assets/icons/edit.svg';
import { CartStrategy } from 'libs/queries';
import { CSSProperties, FC } from 'react';
import { cn } from 'utils/helpers';
Expand All @@ -13,7 +14,7 @@ import {
} from 'components/strategies/common/utils';
import { Warning } from 'components/common/WarningMessageWithIcon';
import { useMarketPrice } from 'hooks/useMarketPrice';
import { removeStrategyFromCart } from './utils';
import { removeStrategyFromCart, useCartEdit } from './utils';
import { useWagmi } from 'libs/wagmi';

interface Props {
Expand Down Expand Up @@ -50,6 +51,7 @@ export const CartStrategyItems: FC<Props> = (props) => {
const { base, quote } = strategy;
const { marketPrice } = useMarketPrice({ base, quote });
const { user } = useWagmi();
const navToEdit = useCartEdit();

const warningMsg = getWarning(strategy, marketPrice);

Expand All @@ -58,6 +60,10 @@ export const CartStrategyItems: FC<Props> = (props) => {
removeStrategyFromCart(user, strategy);
};

const edit = () => {
navToEdit(strategy);
};

return (
<li
id={strategy.id}
Expand All @@ -73,6 +79,15 @@ export const CartStrategyItems: FC<Props> = (props) => {
<PairName baseToken={base} quoteToken={quote} />
</h3>
<div role="menubar" className="ml-auto flex gap-8">
<button
role="menuitem"
type="button"
className="size-38 rounded-6 border-background-800 grid place-items-center border-2 hover:bg-white/10 active:bg-white/20"
aria-label="Edit strategy"
onClick={edit}
>
<IconEdit className="size-16" />
</button>
<button
role="menuitem"
type="button"
Expand Down
99 changes: 99 additions & 0 deletions src/components/cart/EditStrategyCartForm.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
import { FC, FormEvent, ReactNode, useState } from 'react';
import { Token } from 'libs/tokens';
import { Link, useNavigate, useParams } from 'libs/routing';
import { Button } from 'components/common/button';
import { cn } from 'utils/helpers';
import { BaseOrder } from 'components/strategies/common/types';
import { useWagmi } from 'libs/wagmi';
import { lsService } from 'services/localeStorage';
import style from 'components/strategies/common/form.module.css';
import { buttonStyles } from 'components/common/button/buttonStyles';

interface FormProps {
base: Token;
quote: Token;
order0: BaseOrder;
order1: BaseOrder;
approvalText?: string;
children: ReactNode;
}

export const EditStrategyCartForm: FC<FormProps> = (props) => {
const { base, quote, order0, order1, children } = props;
const { strategyId } = useParams({ from: '/cart/edit/$strategyId' });
const { user } = useWagmi();
const nav = useNavigate();
const [hasChanged, setHasChanged] = useState(false);

Check warning on line 26 in src/components/cart/EditStrategyCartForm.tsx

View workflow job for this annotation

GitHub Actions / Lint (20.x)

'hasChanged' is assigned a value but never used. Allowed unused vars must match /^_/u

const isDisabled = (form: HTMLFormElement) => {
if (!form.checkValidity()) return true;
if (!!form.querySelector('.loading-message')) return true;
if (!!form.querySelector('.error-message')) return true;
const warnings = form.querySelector('.warning-message');
if (!warnings) return false;
return !form.querySelector<HTMLInputElement>('#approve-warnings')?.checked;
};

const edit = (e: FormEvent<HTMLFormElement>) => {
e.preventDefault();
if (isDisabled(e.currentTarget)) return;
if (!user) return;
const current = lsService.getItem('carts') || {};
const strategies = current[user];
if (!strategies?.length) return;
const index = strategies.findIndex(({ id }) => id === strategyId);
if (index === -1) return;
current[user][index] = {
id: strategyId,
base: base.address,
quote: quote.address,
order0: { ...order0, marginalPrice: order0.marginalPrice ?? '' },
order1: { ...order1, marginalPrice: order1.marginalPrice ?? '' },
};
lsService.setItem('carts', current);
nav({ to: '/cart' });
};

return (
<form
onChange={() => setHasChanged(true)}
onSubmit={edit}
className={cn(style.form, 'flex flex-1 flex-col gap-20')}
data-testid="create-strategy-form"
>
{children}
<label
htmlFor="approve-warnings"
className={cn(
style.approveWarnings,
'rounded-10 bg-background-900 text-14 font-weight-500 flex items-center gap-8 p-20 text-white/60'
)}
>
<input
id="approve-warnings"
type="checkbox"
className="size-18"
data-testid="approve-warnings"
/>
{props.approvalText ??
"I've reviewed the warning(s) but choose to proceed."}
</label>

<Button
type="submit"
variant="success"
size="lg"
fullWidth
data-testid="edit-submit"
>
Confirm Change
</Button>
<Link
to="/cart"
className={buttonStyles({ variant: 'secondary', size: 'lg' })}
>
Cancel
</Link>
</form>
);
};
80 changes: 79 additions & 1 deletion src/components/cart/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,13 @@ import { lsService } from 'services/localeStorage';
import { useWagmi } from 'libs/wagmi';
import strategyStyle from 'components/strategies/overview/StrategyContent.module.css';
import formStyle from 'components/strategies/common/form.module.css';
import { useNavigate } from '@tanstack/react-router';
import {
getStrategyType,
isLimitOrder,
} from 'components/strategies/common/utils';
import { isGasTokenToHide, NATIVE_TOKEN_ADDRESS } from 'utils/tokens';
import { getRoundedSpread } from 'components/strategies/overlapping/utils';

export type Cart = (CreateStrategyParams & { id: string })[];

Expand All @@ -22,9 +29,15 @@ const toOrder = (sdkOrder: CreateStrategyOrder) => ({
marginalRate: sdkOrder.marginalPrice,
});

const initCart = (user?: string) => {
if (!user) return [];
const carts = lsService.getItem('carts') ?? {};
return carts[user] || [];
};

export const useStrategyCart = () => {
const [cart, setCart] = useState<Cart>([]);
const { user } = useWagmi();
const [cart, setCart] = useState<Cart>(initCart(user));
const { getTokenById } = useTokens();
const { selectedFiatCurrency } = useFiatCurrency();

Expand Down Expand Up @@ -179,3 +192,68 @@ export const clearCart = (user: string) => {
current[user] = [];
lsService.setItem('carts', current);
};

export const useCartEdit = () => {
const navigate = useNavigate();
return (strategy: CartStrategy) => {
const type = getStrategyType(strategy);
const { base, quote, order0, order1 } = strategy;
let baseAddress = base.address;
let quoteAddress = quote.address;

// Force native token address if gas token is different
if (isGasTokenToHide(baseAddress)) baseAddress = NATIVE_TOKEN_ADDRESS;
if (isGasTokenToHide(quoteAddress)) quoteAddress = NATIVE_TOKEN_ADDRESS;

switch (type) {
case 'disposable': {
const isBuyEmpty = !+order0.endRate;
const order = isBuyEmpty ? order1 : order0;
return navigate({
to: '/cart/edit/$strategyId/disposable',
params: { strategyId: strategy.id },
search: {
base: baseAddress,
quote: quoteAddress,
min: order.startRate,
max: order.endRate,
budget: order.balance,
settings: isLimitOrder(order) ? 'limit' : 'range',
direction: isBuyEmpty ? 'sell' : 'buy',
},
});
}
case 'overlapping': {
return navigate({
to: '/cart/edit/$strategyId/overlapping',
params: { strategyId: strategy.id },
search: {
base: baseAddress,
quote: quoteAddress,
min: order0.startRate,
max: order1.endRate,
spread: getRoundedSpread({ order0, order1 }).toString(),
},
});
}
case 'recurring': {
return navigate({
to: '/cart/edit/$strategyId/recurring',
params: { strategyId: strategy.id },
search: {
base: baseAddress,
quote: quoteAddress,
buyMin: order0.startRate,
buyMax: order0.endRate,
buyBudget: order0.balance,
buySettings: isLimitOrder(order0) ? 'limit' : 'range',
sellMin: order1.startRate,
sellMax: order1.endRate,
sellBudget: order1.balance,
sellSettings: isLimitOrder(order1) ? 'limit' : 'range',
},
});
}
}
};
};
1 change: 1 addition & 0 deletions src/components/strategies/common/useSetOrder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ type RecurringUrl =
| '/strategies/edit/$strategyId/budget/disposable'
| '/strategies/edit/$strategyId/budget/recurring'
| '/strategies/edit/$strategyId/prices/recurring'
| '/cart/edit/$strategyId/recurring'
| '/trade/recurring';
export const useSetRecurringOrder = <T>(url: RecurringUrl) => {
const navigate = useNavigate({ from: url });
Expand Down
3 changes: 1 addition & 2 deletions src/components/strategies/create/CreateOverlappingBudget.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,9 @@ interface Props {
set: SetOverlapping;
}

const url = '/trade/overlapping';
export const CreateOverlappingBudget: FC<Props> = (props) => {
const { base, quote, order0, order1, marketPrice, set } = props;
const search = useSearch({ from: url });
const search = useSearch({ strict: false });
const { anchor, budget } = search;
const { user } = useWagmi();

Expand Down
3 changes: 1 addition & 2 deletions src/components/strategies/create/CreateOverlappingPrice.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,9 @@ interface Props {
set: SetOverlapping;
}

const url = '/trade/overlapping';
export const CreateOverlappingPrice: FC<Props> = (props) => {
const { base, quote, order0, order1, marketPrice, spread, set } = props;
const search = useSearch({ from: url });
const search = useSearch({ strict: false });
const { anchor } = search;

const aboveMarket = isMinAboveMarket(order0);
Expand Down
64 changes: 1 addition & 63 deletions src/components/strategies/create/useDuplicateStrategy.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { useNavigate } from 'libs/routing';
import { BaseStrategy, CartStrategy } from 'libs/queries';
import { BaseStrategy } from 'libs/queries';
import { getRoundedSpread } from 'components/strategies/overlapping/utils';
import {
getStrategyType,
Expand Down Expand Up @@ -68,65 +68,3 @@ export const useDuplicate = () => {
}
};
};

export const useCartDuplicate = () => {
const navigate = useNavigate();
return (strategy: CartStrategy) => {
const type = getStrategyType(strategy);
const { base, quote, order0, order1 } = strategy;
let baseAddress = base.address;
let quoteAddress = quote.address;

// Force native token address if gas token is different
if (isGasTokenToHide(baseAddress)) baseAddress = NATIVE_TOKEN_ADDRESS;
if (isGasTokenToHide(quoteAddress)) quoteAddress = NATIVE_TOKEN_ADDRESS;

switch (type) {
case 'disposable': {
const isBuyEmpty = !+order0.endRate;
const order = isBuyEmpty ? order1 : order0;
return navigate({
to: '/trade/disposable',
search: {
base: baseAddress,
quote: quoteAddress,
min: order.startRate,
max: order.endRate,
budget: order.balance,
settings: isLimitOrder(order) ? 'limit' : 'range',
direction: isBuyEmpty ? 'sell' : 'buy',
},
});
}
case 'overlapping': {
return navigate({
to: '/trade/overlapping',
search: {
base: baseAddress,
quote: quoteAddress,
min: order0.startRate,
max: order1.endRate,
spread: getRoundedSpread({ order0, order1 }).toString(),
},
});
}
case 'recurring': {
return navigate({
to: '/trade/recurring',
search: {
base: baseAddress,
quote: quoteAddress,
buyMin: order0.startRate,
buyMax: order0.endRate,
buyBudget: order0.balance,
buySettings: isLimitOrder(order0) ? 'limit' : 'range',
sellMin: order1.startRate,
sellMax: order1.endRate,
sellBudget: order1.balance,
sellSettings: isLimitOrder(order1) ? 'limit' : 'range',
},
});
}
}
};
};
5 changes: 3 additions & 2 deletions src/components/trade/TradeLayout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,14 @@ import { TradeNav } from './TradeNav';

interface Props {
children: ReactNode;
from: '/trade' | '/cart/edit/$strategyId';
}

export const TradeLayout: FC<Props> = ({ children }) => {
export const TradeLayout: FC<Props> = ({ children, from }) => {
return (
<section className="flex flex-col gap-20">
<TokenSelection />
<TradeNav />
<TradeNav from={from} />
{children}
</section>
);
Expand Down
Loading

0 comments on commit 9855825

Please sign in to comment.