bigshortbets / market-frontend

BigShortBet$ P2P Market is a cutting-edge peer-to-peer marketplace built on the principles of decentralization that allows direct P2P trading on unique & event-based markets. Enjoy ultra-low fees and no swaps. Powered by $BigSB.
https://app.bigsb.io
GNU General Public License v3.0
2 stars 5 forks source link

Align text by decimal point #130

Open Klapeyron opened 4 months ago

Klapeyron commented 4 months ago

Is your feature request related to a problem? Please describe. Would be great to align prices in all the places by decimal point

Describe the solution you'd like

Zrzut ekranu 2024-07-26 o 11 01 01

image

@autopilot

Klapeyron commented 3 months ago

@autopilot

codeautopilot[bot] commented 3 months ago

Potential solution

To align prices by the decimal point across various components, we need to ensure that the rendering logic and CSS are adjusted accordingly. This involves:

  1. Adding CSS classes to handle decimal alignment.
  2. Modifying the JSX/TSX to apply these classes.
  3. Updating utility functions to format numbers consistently.

How to implement

Step 1: Add CSS for Decimal Alignment

Create a CSS class that aligns text by the decimal point. This can be done using a combination of display: inline-block and text-align: right.

.decimal-align {
  display: inline-block;
  text-align: right;
  width: 100%;
}

Step 2: Update Utility Functions

Ensure that the formatting functions in utils/numberToCurrencyFormat.ts produce strings where the decimal points are aligned.

File: utils/numberToCurrencyFormat.ts

export const numberToCurrencyFormat = (amount: number, decimalPlaces: number, maxIntegerDigits: number = 10) => {
  const parts = amount
    .toLocaleString('en', {
      minimumFractionDigits: decimalPlaces,
      maximumFractionDigits: decimalPlaces,
      useGrouping: false,
    })
    .split('.');

  const integerPart = parts[0].padStart(maxIntegerDigits, ' ');
  const decimalPart = parts[1] || '0'.repeat(decimalPlaces);

  return `${integerPart}.${decimalPart}`;
};

export const toFixedNoRounding = (num: number, decimalPlaces: number) => {
  const regex = new RegExp(`^-?\\d+(?:\\.\\d{0,${decimalPlaces}})?`);
  const match = num.toString().match(regex);
  if (match) {
    const parts = match[0].split('.');
    const integerPart = parts[0];
    const decimalPart = (parts[1] || '').padEnd(decimalPlaces, '0');
    return `${integerPart}.${decimalPart}`;
  }
  return num.toFixed(decimalPlaces);
};

Step 3: Modify Components to Apply CSS and Formatting

File: components/Market/OrderBook/RecentTradesItem.tsx

import { chosenMarketAtom } from '@/store/store';
import { RecentPositionType } from '@/types/positionTypes';
import { getPrecision } from '@/utils/getPrecision';
import { format, parseISO } from 'date-fns';
import { useAtom } from 'jotai';

interface RecentTradesItemProps {
  position: RecentPositionType;
}

export const RecentTradesItem = ({ position }: RecentTradesItemProps) => {
  const [chosenMarket] = useAtom(chosenMarketAtom);
  const precision = getPrecision(Number(chosenMarket?.tickSize));
  const date = parseISO(position.timestamp);
  return (
    <div className='py-1 flex items-center justify-between text-tetriary'>
      <p>{format(date, 'd MMMM HH:mm:ss')}</p>
      <div className='flex items-center'>
        <div className='w-[64px] text-right'>
          <p className='decimal-align'>{Number(position.createPrice).toFixed(precision)}</p>
        </div>
        <div className='w-[64px] text-right'>
          <p>{Number(position.quantity)}</p>
        </div>
      </div>
    </div>
  );
};

File: components/Market/TradingHub/TradingHubOrders/TradingHubOrdersItem.tsx

import { OrderType } from '@/types/orderTypes';
import { SideLabel } from '../SideLabel';
import { useCancelOrder } from '@/blockchain/hooks/useCancelOrder';
import { format, parseISO } from 'date-fns';
import { getMarkeDetails } from '@/utils/getMarketDetails';
import { useAccount } from 'wagmi';
import { useEffect, useState } from 'react';
import { fetchOrderCollateral } from '@/utils/fetchOrderCollateral';
import { numberToCurrencyFormat } from '@/utils/numberToCurrencyFormat';

interface TradingHubOrdersItemProps {
  order: OrderType;
}

export const TradingHubOrdersItem = ({ order }: TradingHubOrdersItemProps) => {
  const { write: writeCancelOrder } = useCancelOrder(order.market.id, order.id);
  const date = parseISO(order.timestamp);
  const marketDetails = getMarkeDetails(order.market.ticker);

  const { address } = useAccount();
  const [state, setState] = useState<number>();

  return (
    <tr className={`text-sm odd:bg-[#23252E] text-[#7F828F] overflow-x-scroll sm:text-xs`}>
      <td className='pl-3 py-2'>
        <SideLabel side={order.side} />
      </td>
      <td>{format(date, 'd MMMM yyyy HH:mm:ss')}</td>
      <td>{marketDetails?.name}</td>
      <td className="price-column">{numberToCurrencyFormat(order.price, 2)}</td>
      <td>{Number(order.quantity)}</td>
      <td className='text-right pr-3'>
        <button
          className={`font-bold text-xs text-[#D26D6C] transition ease-in-out hover:text-[#C53F3A] duration-300`}
          onClick={() => writeCancelOrder()}
        >
          CANCEL
        </button>
      </td>
    </tr>
  );
};

File: components/Market/OrderBook/OrderBookItem.tsx

import { useEffect, useState } from 'react';
import { OrderSide } from './OrderBook';
import { OrderBookOrder } from '@/types/orderTypes';
import { fetchOrderCollateral } from '@/utils/fetchOrderCollateral';
import { useAccount } from 'wagmi';
import { useAtom } from 'jotai';
import { chosenMarketAtom } from '@/store/store';
import { getPrecision } from '@/utils/getPrecision';

interface OrderBookItem {
  empty: boolean;
  side: OrderSide;
  data?: OrderBookOrder;
}

export const OrderBookItem = ({ empty, side, data }: OrderBookItem) => {
  const [chosenMarket] = useAtom(chosenMarketAtom);

  const precision = getPrecision(Number(chosenMarket?.tickSize));

  const formatPrice = (price: number) => {
    const [integerPart, fractionalPart] = price.toFixed(precision).split('.');
    return { integerPart, fractionalPart };
  };

  return (
    <div
      className={`w-full bg-opacity-[15%] text-opacity-50 py-2 ${
        side === OrderSide.LONG
          ? 'bg-green-900 text-tetriary'
          : 'bg-[#C53F3A] text-tetriary'
      }`}
    >
      {!empty && data && (
        <div className='w-full justify-between h-full flex px-4 text-xs'>
          <div className='text-right min-w-[60px] flex'>
            {(() => {
              const { integerPart, fractionalPart } = formatPrice(Number(data.price));
              return (
                <>
                  <span>{integerPart}</span>
                  <span>.{fractionalPart}</span>
                </>
              );
            })()}
          </div>
          <div>{data.quantity}</div>
        </div>
      )}
    </div>
  );
};

File: components/Market/TradingHub/TradingHubPositions/TradingHubPositionsItem.tsx

import { PositionWithSide } from '@/types/positionTypes';
import { useState } from 'react';
import { SideLabel } from '../SideLabel';
import { truncateAddress } from '@/utils/truncateAddress';
import { getOpponentMarginData } from '@/utils/getOpponentMarginData';
import { opponentsMarginsAtom } from '../../Market';
import { useAtom } from 'jotai';
import { LiquidationStatusTab } from '../../LiquidationStatusTab';
import { LiquidationStatusType } from '@/blockchain/hooks/useUserMargin';
import { Tooltip } from 'react-tooltip';
import { useMarkToMarket } from '@/blockchain/hooks/useMarkToMarket';
import { ClosePositionModal } from './ClosePositionModal';
import { currencySymbol } from '@/blockchain/constants';
import { getMarkeDetails } from '@/utils/getMarketDetails';
import { FaMessage } from 'react-icons/fa6';
import { tradingHubStateAtom } from '@/store/store';

interface TradingHubPositionsItemProps {
  position: PositionWithSide;
  isNotAggregated?: boolean;
}

export const TradingHubPositionsItem = ({
  position,
  isNotAggregated,
}: TradingHubPositionsItemProps) => {
  const oraclePrice = position.market.oraclePrice;
  const opponent = position.side === 'LONG' ? position.short : position.long;
  const calculatedProfitOrLoss =
    position.side === 'LONG'
      ? Number(position.quantityLeft) *
        Number(position.market.contractUnit) *
        (Number(oraclePrice.toString()) -
          Number(position.createPriceLong.toString()))
      : Number(position.quantityLeft) *
        Number(position.market.contractUnit) *
        (Number(position.createPriceShort.toString()) -
          Number(oraclePrice.toString()));

  const { write: writeMarkToMarket } = useMarkToMarket(
    position.market.id,
    position.id
  );

  const [opponentsMargin] = useAtom(opponentsMarginsAtom);

  const marginData = getOpponentMarginData(
    opponentsMargin,
    opponent,
    position.market.id
  );

  const [isModalOpened, setIsModalOpened] = useState<boolean>(false);

  const handleCloseModal = () => {
    setIsModalOpened(false);
  };
  const marketDetails = getMarkeDetails(position.market.ticker);

  const [_, setTradingHubState] = useAtom(tradingHubStateAtom);

  const formatPrice = (price: number) => {
    const [integerPart, decimalPart] = price.toFixed(2).split('.');
    return { integerPart, decimalPart };
  };

  const createPrice = position.side === 'LONG'
    ? formatPrice(Number(position.createPriceLong))
    : formatPrice(Number(position.createPriceShort));

  const currentPrice = formatPrice(Number(position.price));

  return (
    <tr
      className={`text-sm even:bg-[#23252E] text-[#7F828F]  overflow-x-scroll
  }`}
    >
      <td className='px-6 sm:pr-0 sm:pl-3 py-3'>
        <SideLabel side={position.side} />
      </td>
      {isNotAggregated && (
        <td className='text-[10px] sm:text-xs px-6 sm:px-0'>
          {marketDetails?.name}
        </td>
      )}
      <td className='text-[10px] sm:text-xs px-6 sm:px-0'>
        {Number(position.quantityLeft)}
      </td>
      <td className='text-[10px] sm:text-xs px-6 sm:px-0 decimal-align' data-decimal={createPrice.decimalPart}>
        {createPrice.integerPart}
      </td>
      <td className='text-[10px] sm:text-xs px-6 sm:px-0 decimal-align' data-decimal={currentPrice.decimalPart}>
        {currentPrice.integerPart}
      </td>
      <td
        className={`${
          calculatedProfitOrLoss < 0
            ? 'text-red-500'
            : 'text-[#73D391] font-semibold'
        } text-[10px] sm:text-xs px-6 sm:px-0`}
      >
        {calculatedProfitOrLoss.toFixed(2)}{' '}
        <span className={`text-[10px] sm:text-xs`}>{currencySymbol}</span>
      </td>
      <td className='align-middle px-6 sm:px-0 '>
        <div className='flex items-center space-x-2'>
          <p className='text-[10px] sm:text-xs'>{truncateAddress(opponent)}</p>
          <LiquidationStatusTab
            status={marginData?.liquidationStatus! as LiquidationStatusType}
            small
          />

          {/* CHAT LOGIC */}

          {/*  <button onClick={() => setTradingHubState('chat')}>
            <FaMessage className='text-sm' />
          </button> */}

          {/*  */}
        </div>
      </td>
      <td className=' text-right pr-3 hidden sm:table-cell'>
        <a
          data-tooltip-id='m2m-tooltip'
          data-tooltip-html='Mark-to-Market (MTM): Instantly updates your</br> asset values based  on current market conditions.</br> On our peer-to-peer market, this action is </br>executed on demand, ensuring transparency without</br> daily automatic adjustments.'
        >
          <button
            className='mr-4 text-xs font-semibold text-[#4ECB7D] hover:underline'
            onClick={() => writeMarkToMarket()}
          >
            MTM
          </button>
        </a>

        <button
          onClick={() => setIsModalOpened(true)}
          className={`font-bold text-xs hover:underline transition ease-in-out text-[#C53F3A] duration-300`}
        >
          CLOSE
        </button>
      </td>
      <td className='sm:hidden sm:pr-3 sm:pl-0 text-right px-6 '>
        {' '}
        <a
          data-tooltip-id='m2m-tooltip'
          data-tooltip-html='Mark-to-Market (MTM): Instantly updates your</br> asset values based  on current market conditions.</br> On our peer-to-peer market, this action is </br>executed on demand, ensuring transparency without</br> daily automatic adjustments.'
        >
          <button
            className='mr-4 text-[10px] sm:text-xs font-semibold text-[#4ECB7D] hover:underline '
            onClick={() => writeMarkToMarket()}
          >
            MTM
          </button>
        </a>
      </td>
      <td className='sm:hidden sm:pr-3 sm:pl-0 px-6  '>
        <button
          onClick={() => setIsModalOpened(true)}
          className={`font-bold text-[10px] sm:text-xs hover:underline transition ease-in-out text-[#C53F3A] duration-300`}
        >
          CLOSE
        </button>
      </td>
      <Tooltip id='m2m-tooltip' />
      <ClosePositionModal
        handleCloseModal={handleCloseModal}
        isModalOpened={isModalOpened}
        position={position}
      />
    </tr>
  );
};

Summary

  1. CSS for Decimal Alignment: Added a CSS class to align text by the decimal point.
  2. Utility Functions: Updated utility functions to format numbers consistently.
  3. Component Updates: Modified components to apply the CSS class and use the updated utility functions.

This approach ensures that prices are consistently aligned by the decimal point across different components, improving readability and consistency throughout the application.

Click here to create a Pull Request with the proposed solution

Files used for this task:

Changes on components/Market/OrderBook/RecentTradesItem.tsx To align prices by the decimal point in the `RecentTradesItem` component, we need to modify the rendering logic. This can be achieved by using CSS to ensure that the decimal points are aligned. Here's a step-by-step proposal to implement this: 1. **Update the CSS**: Add a CSS class that aligns text by the decimal point. 2. **Modify the JSX**: Apply the CSS class to the price elements. ### Step-by-Step Implementation 1. **Add CSS for Decimal Alignment**: Create a CSS class that aligns text by the decimal point. This can be done using a combination of `display: inline-block` and `text-align: right`. ```css .decimal-align { display: inline-block; text-align: right; width: 100%; } ``` 2. **Modify the JSX in `RecentTradesItem`**: Apply the CSS class to the price elements to ensure they are aligned by the decimal point. ```tsx import { chosenMarketAtom } from '@/store/store'; import { RecentPositionType } from '@/types/positionTypes'; import { getPrecision } from '@/utils/getPrecision'; import { format, parseISO } from 'date-fns'; import { useAtom } from 'jotai'; interface RecentTradesItemProps { position: RecentPositionType; } export const RecentTradesItem = ({ position }: RecentTradesItemProps) => { const [chosenMarket] = useAtom(chosenMarketAtom); const precision = getPrecision(Number(chosenMarket?.tickSize)); const date = parseISO(position.timestamp); return (

{format(date, 'd MMMM HH:mm:ss')}

{Number(position.createPrice).toFixed(precision)}

{Number(position.quantity)}

); }; ``` ### Explanation - **CSS Class**: The `.decimal-align` class ensures that the text within the element is aligned by the decimal point. - **JSX Modification**: The `className='decimal-align'` is added to the price element to apply the CSS class. This approach ensures that prices are aligned by the decimal point across the `RecentTradesItem` component. Similar changes can be applied to other components mentioned in the task to achieve consistent alignment throughout the application.
Changes on utils/numberToCurrencyFormat.ts To align prices by the decimal point, we need to ensure that the formatting functions in `utils/numberToCurrencyFormat.ts` produce strings where the decimal points are aligned. This can be achieved by padding the integer part of the number with spaces or zeros to ensure consistent width. Here's a concrete proposal to update the formatting functions: 1. **Update `numberToCurrencyFormat` function**: - Modify the function to pad the integer part of the number with spaces to ensure consistent width. - Ensure that the decimal part is also consistently formatted. 2. **Update `toFixedNoRounding` function**: - Ensure that this function also aligns the decimal points if used in the rendering logic. ### Updated Code ```typescript export const numberToCurrencyFormat = (amount: number, decimalPlaces: number, maxIntegerDigits: number = 10) => { const parts = amount .toLocaleString('en', { minimumFractionDigits: decimalPlaces, maximumFractionDigits: decimalPlaces, useGrouping: false, }) .split('.'); const integerPart = parts[0].padStart(maxIntegerDigits, ' '); const decimalPart = parts[1] || '0'.repeat(decimalPlaces); return `${integerPart}.${decimalPart}`; }; export const toFixedNoRounding = (num: number, decimalPlaces: number) => { const regex = new RegExp(`^-?\\d+(?:\\.\\d{0,${decimalPlaces}})?`); const match = num.toString().match(regex); if (match) { const parts = match[0].split('.'); const integerPart = parts[0]; const decimalPart = (parts[1] || '').padEnd(decimalPlaces, '0'); return `${integerPart}.${decimalPart}`; } return num.toFixed(decimalPlaces); }; ``` ### Explanation 1. **`numberToCurrencyFormat` Function**: - The function now takes an additional parameter `maxIntegerDigits` to specify the maximum width of the integer part. - The integer part is padded with spaces to ensure consistent width. - The decimal part is ensured to have the specified number of decimal places. 2. **`toFixedNoRounding` Function**: - The function now takes an additional parameter `decimalPlaces` to specify the number of decimal places. - The integer and decimal parts are processed to ensure consistent formatting. ### Next Steps 1. **Update Rendering Logic**: - Ensure that the components `OrderBookItem.tsx`, `RecentTradesItem.tsx`, `TradingHubOrdersItem.tsx`, and `TradingHubPositionsItem.tsx` use these updated functions to format prices. 2. **Testing**: - Test the changes in various scenarios to ensure that prices are aligned correctly by the decimal point. By following this approach, you will ensure that prices are consistently aligned by the decimal point across different components.
Changes on components/Market/TradingHub/TradingHubOrders/TradingHubOrdersItem.tsx To align prices by the decimal point in the `TradingHubOrdersItem.tsx` file, you need to modify the rendering logic for the price field. This can be achieved by using CSS to align the text properly. Here's a step-by-step guide to implement this: 1. **Update the Price Formatting**: Ensure that the price is formatted as a string with a fixed number of decimal places. 2. **CSS Styling**: Use CSS to align the text by the decimal point. ### Step-by-Step Implementation 1. **Update the Price Formatting**: Modify the price rendering to ensure it is formatted as a string with a fixed number of decimal places. ```tsx // Import the number formatting utility import { numberToCurrencyFormat } from '@/utils/numberToCurrencyFormat'; // Inside the component {numberToCurrencyFormat(order.price)} ``` 2. **CSS Styling**: Add CSS to align the text by the decimal point. This can be done by using a monospace font and ensuring the decimal points align. ```css .price-column { font-family: 'Courier New', Courier, monospace; /* Use a monospace font */ text-align: right; /* Align text to the right */ } ``` 3. **Update the Component**: Ensure the component uses the updated CSS class. ```tsx import { OrderType } from '@/types/orderTypes'; import { SideLabel } from '../SideLabel'; import { useCancelOrder } from '@/blockchain/hooks/useCancelOrder'; import { format, parseISO } from 'date-fns'; import { getMarkeDetails } from '@/utils/getMarketDetails'; import { useAccount } from 'wagmi'; import { useEffect, useState } from 'react'; import { fetchOrderCollateral } from '@/utils/fetchOrderCollateral'; import { numberToCurrencyFormat } from '@/utils/numberToCurrencyFormat'; // Import the utility interface TradingHubOrdersItemProps { order: OrderType; } export const TradingHubOrdersItem = ({ order }: TradingHubOrdersItemProps) => { const { write: writeCancelOrder } = useCancelOrder(order.market.id, order.id); const date = parseISO(order.timestamp); const marketDetails = getMarkeDetails(order.market.ticker); const { address } = useAccount(); const [state, setState] = useState(); return ( {/* Side */} {/* Created */} {format(date, 'd MMMM yyyy HH:mm:ss')} {/* Market */} {marketDetails?.name} {/* Price */} {numberToCurrencyFormat(order.price)} {/* Quantity */} {Number(order.quantity)} {/* Close */} ); }; ``` ### Summary 1. **Format the price** using a utility function to ensure consistent decimal places. 2. **Apply CSS styling** to align the text by the decimal point using a monospace font and right alignment. This approach ensures that prices are visually aligned by their decimal points, improving readability.
Changes on components/Market/OrderBook/OrderBookItem.tsx To align prices by the decimal point in the `OrderBookItem.tsx` file, you need to modify the rendering logic to ensure that the decimal points are aligned. This can be achieved by splitting the price into two parts: the integer part and the fractional part, and then rendering them in a way that aligns the decimal points. Here's a step-by-step guide to modify the `OrderBookItem.tsx` file: 1. **Split the Price into Integer and Fractional Parts**: - Use JavaScript string manipulation to split the price into the integer and fractional parts. 2. **Render the Parts Separately**: - Render the integer part and fractional part in separate spans or divs with appropriate styling to ensure alignment. 3. **CSS for Alignment**: - Use CSS to ensure that the parts are aligned properly. Here is the modified code: ```tsx import { useEffect, useState } from 'react'; import { OrderSide } from './OrderBook'; import { OrderBookOrder } from '@/types/orderTypes'; import { fetchOrderCollateral } from '@/utils/fetchOrderCollateral'; import { useAccount } from 'wagmi'; import { useAtom } from 'jotai'; import { chosenMarketAtom } from '@/store/store'; import { getPrecision } from '@/utils/getPrecision'; interface OrderBookItem { empty: boolean; side: OrderSide; data?: OrderBookOrder; } export const OrderBookItem = ({ empty, side, data }: OrderBookItem) => { const [chosenMarket] = useAtom(chosenMarketAtom); const precision = getPrecision(Number(chosenMarket?.tickSize)); const formatPrice = (price: number) => { const [integerPart, fractionalPart] = price.toFixed(precision).split('.'); return { integerPart, fractionalPart }; }; return (
{!empty && data && (
{(() => { const { integerPart, fractionalPart } = formatPrice(Number(data.price)); return ( <> {integerPart} .{fractionalPart} ); })()}
{data.quantity}
)}
); }; ``` ### Explanation: 1. **`formatPrice` Function**: - This function takes a price, formats it to the required precision, and splits it into integer and fractional parts. 2. **Rendering Logic**: - Inside the `div` with `className='text-right min-w-[60px] flex'`, the price is split into integer and fractional parts and rendered separately to ensure alignment. 3. **CSS Flexbox**: - The `flex` class ensures that the integer and fractional parts are displayed inline and can be aligned properly. This approach ensures that prices are aligned by the decimal point, providing a cleaner and more readable display of prices.
Changes on components/Market/TradingHub/TradingHubPositions/TradingHubPositionsItem.tsx To align prices by the decimal point in the `TradingHubPositionsItem.tsx` file, you need to modify the rendering logic of the price-related fields. This can be achieved by using CSS to align the text properly. Here’s a step-by-step guide to implement this: 1. **Update the CSS**: Add a CSS class to align text by the decimal point. 2. **Apply the CSS Class**: Apply this CSS class to the relevant table cells where prices are displayed. ### Step 1: Update the CSS First, you need to define a CSS class that aligns text by the decimal point. You can add this CSS in your global stylesheet or within a CSS module if you are using one. ```css .decimal-align { text-align: right; display: inline-block; position: relative; } .decimal-align::after { content: attr(data-decimal); visibility: hidden; display: inline-block; width: 0; } ``` ### Step 2: Apply the CSS Class Next, you need to apply this CSS class to the relevant table cells in the `TradingHubPositionsItem.tsx` file. You will also need to modify the rendering logic to include the decimal part as a data attribute. Here’s how you can do it: ```tsx import { PositionWithSide } from '@/types/positionTypes'; import { useState } from 'react'; import { SideLabel } from '../SideLabel'; import { truncateAddress } from '@/utils/truncateAddress'; import { getOpponentMarginData } from '@/utils/getOpponentMarginData'; import { opponentsMarginsAtom } from '../../Market'; import { useAtom } from 'jotai'; import { LiquidationStatusTab } from '../../LiquidationStatusTab'; import { LiquidationStatusType } from '@/blockchain/hooks/useUserMargin'; import { Tooltip } from 'react-tooltip'; import { useMarkToMarket } from '@/blockchain/hooks/useMarkToMarket'; import { ClosePositionModal } from './ClosePositionModal'; import { currencySymbol } from '@/blockchain/constants'; import { getMarkeDetails } from '@/utils/getMarketDetails'; import { FaMessage } from 'react-icons/fa6'; import { tradingHubStateAtom } from '@/store/store'; interface TradingHubPositionsItemProps { position: PositionWithSide; isNotAggregated?: boolean; } export const TradingHubPositionsItem = ({ position, isNotAggregated, }: TradingHubPositionsItemProps) => { const oraclePrice = position.market.oraclePrice; const opponent = position.side === 'LONG' ? position.short : position.long; const calculatedProfitOrLoss = position.side === 'LONG' ? Number(position.quantityLeft) * Number(position.market.contractUnit) * (Number(oraclePrice.toString()) - Number(position.createPriceLong.toString())) : Number(position.quantityLeft) * Number(position.market.contractUnit) * (Number(position.createPriceShort.toString()) - Number(oraclePrice.toString())); const { write: writeMarkToMarket } = useMarkToMarket( position.market.id, position.id ); const [opponentsMargin] = useAtom(opponentsMarginsAtom); const marginData = getOpponentMarginData( opponentsMargin, opponent, position.market.id ); const [isModalOpened, setIsModalOpened] = useState(false); const handleCloseModal = () => { setIsModalOpened(false); }; const marketDetails = getMarkeDetails(position.market.ticker); const [_, setTradingHubState] = useAtom(tradingHubStateAtom); const formatPrice = (price: number) => { const [integerPart, decimalPart] = price.toFixed(2).split('.'); return { integerPart, decimalPart }; }; const createPrice = position.side === 'LONG' ? formatPrice(Number(position.createPriceLong)) : formatPrice(Number(position.createPriceShort)); const currentPrice = formatPrice(Number(position.price)); return ( {isNotAggregated && ( {marketDetails?.name} )} {Number(position.quantityLeft)} {createPrice.integerPart} {currentPrice.integerPart} {calculatedProfitOrLoss.toFixed(2)}{' '} {currencySymbol}

{truncateAddress(opponent)}

{/* CHAT LOGIC */} {/* */} {/* */}
{' '} ); }; ``` ### Explanation 1. **CSS Class**: The `decimal-align` class ensures that the text is aligned by the decimal point. 2. **Data Attribute**: The `data-decimal` attribute is used to store the decimal part of the price, which helps in aligning the text correctly. 3. **Formatting Function**: The `formatPrice` function splits the price into integer and decimal parts. 4. **Applying CSS**: The `decimal-align` class and `data-decimal` attribute are applied to the relevant table cells. This approach ensures that prices are aligned by the decimal point, improving readability and consistency across the application.