Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ const styleSheet = () =>
justifyContent: 'flex-end',
alignItems: 'flex-end',
},
skeletonSpacing: {
marginBottom: 4,
},
marketEntry: {
flexDirection: 'column',
justifyContent: 'space-between',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -211,4 +211,33 @@ describe('PredictPosition', () => {
expect(screen.getByText('$100.75')).toBeOnTheScreen();
expect(screen.getByText('+15.75%')).toBeOnTheScreen();
});

describe('optimistic updates UI', () => {
it('hides current value when position is optimistic', () => {
renderComponent({ optimistic: true, currentValue: 2345.67 });

expect(screen.queryByText('$2,345.67')).toBeNull();
});

it('hides percent PnL when position is optimistic', () => {
renderComponent({ optimistic: true, percentPnl: 5.25 });

expect(screen.queryByText('+5.25%')).toBeNull();
});

it('shows actual values when position is not optimistic', () => {
renderComponent({ optimistic: false });

expect(screen.getByText('$2,345.67')).toBeOnTheScreen();
expect(screen.getByText('+5.25%')).toBeOnTheScreen();
});

it('shows initial value line when optimistic', () => {
renderComponent({ optimistic: true, initialValue: 123.45 });

expect(
screen.getByText('$123.45 on Yes · 10 shares at 34¢'),
).toBeOnTheScreen();
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {
import styleSheet from './PredictPosition.styles';
import { PredictPositionSelectorsIDs } from '../../../../../../e2e/selectors/Predict/Predict.selectors';
import { strings } from '../../../../../../locales/i18n';
import { Skeleton } from '../../../../../component-library/components/Skeleton';

interface PredictPositionProps {
position: PredictPositionType;
Expand All @@ -34,6 +35,7 @@ const PredictPosition: React.FC<PredictPositionProps> = ({
avgPrice,
currentValue,
size,
optimistic,
} = position;
const { styles } = useStyles(styleSheet, {});

Expand Down Expand Up @@ -71,15 +73,24 @@ const PredictPosition: React.FC<PredictPositionProps> = ({
</Text>
</View>
<View style={styles.positionPnl}>
<Text variant={TextVariant.BodyMDMedium} color={TextColor.Default}>
{formatPrice(currentValue, { maximumDecimals: 2 })}
</Text>
<Text
variant={TextVariant.BodySMMedium}
color={percentPnl > 0 ? TextColor.Success : TextColor.Error}
>
{formatPercentage(percentPnl)}
</Text>
{optimistic ? (
<>
<Skeleton width={60} height={20} style={styles.skeletonSpacing} />
<Skeleton width={50} height={16} />
</>
) : (
<>
<Text variant={TextVariant.BodyMDMedium} color={TextColor.Default}>
{formatPrice(currentValue, { maximumDecimals: 2 })}
</Text>
<Text
variant={TextVariant.BodySMMedium}
color={percentPnl > 0 ? TextColor.Success : TextColor.Error}
>
{formatPercentage(percentPnl)}
</Text>
</>
)}
</View>
</TouchableOpacity>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -250,4 +250,26 @@ describe('PredictPositionDetail', () => {
}),
});
});

describe('optimistic updates UI', () => {
it('hides current value when position is optimistic and market is open', () => {
renderComponent({ optimistic: true, currentValue: 500 });

expect(screen.queryByText('$500.00')).toBeNull();
});

it('hides percent PnL when position is optimistic and market is open', () => {
renderComponent({ optimistic: true, percentPnl: 12.34 });

expect(screen.queryByText('+12.34%')).toBeNull();
});

it('shows initial value and outcome when position is optimistic', () => {
renderComponent({ optimistic: true, initialValue: 123.45 });

expect(
screen.getByText('$123.45 on Yes • 34¢', { exact: false }),
).toBeOnTheScreen();
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import { PredictEventValues } from '../../constants/eventNames';
import { strings } from '../../../../../../locales/i18n';
import { usePredictActionGuard } from '../../hooks/usePredictActionGuard';
import { PredictMarketDetailsSelectorsIDs } from '../../../../../../e2e/selectors/Predict/Predict.selectors';
import { Skeleton } from '../../../../../component-library/components/Skeleton';

interface PredictPositionProps {
position: PredictPositionType;
Expand All @@ -46,6 +47,7 @@ const PredictPosition: React.FC<PredictPositionProps> = ({
avgPrice,
currentValue,
title,
optimistic,
} = position;
const navigation =
useNavigation<NavigationProp<PredictNavigationParamList>>();
Expand Down Expand Up @@ -80,6 +82,11 @@ const PredictPosition: React.FC<PredictPositionProps> = ({
};

const renderValueText = () => {
// Show skeleton for optimistic positions
if (optimistic) {
return <Skeleton width={70} height={20} />;
}

if (marketStatus === PredictMarketStatus.OPEN) {
return (
<Text variant={TextVariant.BodyMDMedium} color={TextColor.Default}>
Expand Down Expand Up @@ -135,14 +142,17 @@ const PredictPosition: React.FC<PredictPositionProps> = ({
</Box>
<Box twClassName="items-end justify-end ml-auto shrink-0">
{renderValueText()}
{marketStatus === PredictMarketStatus.OPEN && (
<Text
variant={TextVariant.BodySMMedium}
color={percentPnl > 0 ? TextColor.Success : TextColor.Error}
>
{formatPercentage(percentPnl)}
</Text>
)}
{marketStatus === PredictMarketStatus.OPEN &&
(optimistic ? (
<Skeleton width={55} height={16} style={tw.style('mt-1')} />
) : (
<Text
variant={TextVariant.BodySMMedium}
color={percentPnl > 0 ? TextColor.Success : TextColor.Error}
>
{formatPercentage(percentPnl)}
</Text>
))}
</Box>
</Box>
{marketStatus === PredictMarketStatus.OPEN && (
Expand All @@ -156,6 +166,7 @@ const PredictPosition: React.FC<PredictPositionProps> = ({
width={ButtonWidthTypes.Full}
label={strings('predict.cash_out')}
onPress={onCashOut}
isDisabled={optimistic}
/>
</Box>
)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1168,14 +1168,15 @@ export class PredictController extends BaseController<
let realSharePrice = sharePrice;
try {
if (preview.side === Side.BUY) {
const totalFee = params.preview.fees?.totalFee ?? 0;
realAmountUsd = parseFloat(spentAmount);
realSharePrice = parseFloat(spentAmount) / parseFloat(receivedAmount);

// Optimistically update balance
this.update((state) => {
state.balances[providerId] = state.balances[providerId] || {};
state.balances[providerId][signer.address] = {
balance: cachedBalance - realAmountUsd,
balance: cachedBalance - (realAmountUsd + totalFee),
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a quick fix to the optimistic balance updates, which were missing the fees.

// valid for 5 seconds (since it takes some time to reflect balance on-chain)
validUntil: Date.now() + 5000,
};
Expand Down
1 change: 1 addition & 0 deletions app/components/UI/Predict/hooks/usePredictPrices.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@ export const usePredictPrices = (
setIsFetching(false);
}
}
// eslint-disable-next-line react-compiler/react-compiler
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [enabled, queriesKey, providerId, pollingInterval]);

Expand Down
Loading
Loading