Skip to content

Commit

Permalink
Merge pull request #53 from ahmadtaimoor-deriv/f_contract_details
Browse files Browse the repository at this point in the history
chore: Cancel Close Contracts and TP,SL actions
  • Loading branch information
akmal-deriv authored Jun 5, 2024
2 parents d92b035 + 0b3eb80 commit 1804b43
Show file tree
Hide file tree
Showing 15 changed files with 362 additions and 137 deletions.
6 changes: 0 additions & 6 deletions packages/trader/src/AppV2/Components/BottomNav/bottom-nav.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import {
} from '@deriv/quill-icons';
import BottomNavItem from './bottom-nav-item';
import { Badge } from '@deriv-com/quill-ui';
import ContractDetailsFooter from '../ContractDetailsFooter';

type BottomNavProps = {
className?: string;
Expand Down Expand Up @@ -47,10 +46,6 @@ const bottomNavItems = [
icon: <StandaloneBarsRegularIcon iconSize='sm' fill='var(--semantic-color-monochrome-textIcon-normal-high)' />,
label: <Localize i18n_default_text='Menu' />,
},
{
icon: <StandaloneBarsRegularIcon iconSize='sm' fill='var(--semantic-color-monochrome-textIcon-normal-high)' />,
label: <Localize i18n_default_text='Details' />,
},
];

const BottomNav = ({ className, children }: BottomNavProps) => {
Expand All @@ -59,7 +54,6 @@ const BottomNav = ({ className, children }: BottomNavProps) => {
return (
<div className={classNames('bottom-nav', className)}>
<div className='bottom-nav-selection'>{children[selectedIndex]}</div>
{selectedIndex === 4 && <ContractDetailsFooter />}
<div className='bottom-nav-container'>
{bottomNavItems.map((item, index) => (
<BottomNavItem
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,7 @@
gap: var(--semantic-spacing-gap-md);
width: 100%;
box-shadow: var(--core-elevation-shadow-210);
position: fixed;
bottom: 0;
}
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,80 @@
import { Button } from '@deriv-com/quill-ui';
import { TContractInfo, getCardLabels, isMultiplierContract, isValidToCancel, isValidToSell } from '@deriv/shared';
import { useStore } from '@deriv/stores';
import { getRemainingTime } from 'AppV2/Utils/helper';
import { observer } from 'mobx-react';
import React from 'react';

const ContractDetailsFooter = () => {
type ContractInfoProps = {
contract_info: TContractInfo;
};

const ContractDetailsFooter = observer(({ contract_info }: ContractInfoProps) => {
const {
bid_price,
currency,
contract_id,
cancellation: { date_expiry: cancellation_date_expiry } = {},
profit,
contract_type,
} = contract_info;

const { contract_replay, common } = useStore();
const { server_time } = common;
const { onClickCancel, onClickSell, is_sell_requested } = contract_replay;
const is_valid_to_sell = isValidToSell(contract_info);
const is_valid_to_cancel = isValidToCancel(contract_info);
const is_multiplier = isMultiplierContract(contract_type);

return (
<div className='contract-details-footer--container'>
<Button variant='secondary' label='Close @ 9.00 USD' color='black' size='lg' fullWidth />
{is_multiplier ? (
<>
<Button
variant='secondary'
label={`${getCardLabels().CLOSE} ${!is_valid_to_cancel ? `@${bid_price} ${currency}` : ''}`}
color='black'
size='lg'
isLoading={is_sell_requested}
disabled={is_sell_requested || (Number(profit) < 0 && is_valid_to_cancel)}
onClick={() => onClickSell(contract_id)}
fullWidth
/>
{is_valid_to_cancel && (
<Button
onClick={() => onClickCancel(contract_id)}
variant='secondary'
label={`${getCardLabels().CANCEL} ${getRemainingTime({
end_time: cancellation_date_expiry,
format: 'mm:ss',
getCardLabels,
start_time: server_time,
})}`}
color='black'
disabled={Number(profit) >= 0}
size='lg'
fullWidth
/>
)}
</>
) : (
<Button
variant='secondary'
label={
is_valid_to_sell
? `${getCardLabels().CLOSE} @ ${bid_price} ${currency}`
: getCardLabels().RESALE_NOT_OFFERED
}
color='black'
size='lg'
isLoading={is_sell_requested && is_valid_to_sell}
onClick={is_valid_to_sell ? () => onClickSell(contract_id) : undefined}
fullWidth
disabled={!is_valid_to_sell}
/>
)}
</div>
);
};
});

export default ContractDetailsFooter;
44 changes: 21 additions & 23 deletions packages/trader/src/AppV2/Components/OrderDetails/order-details.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,30 +14,28 @@ const OrderDetails = ({ contract_info }: ContractInfoProps) => {
const details = orderDetails ? orderDetails.details : {};
return (
<div className='order-details'>
<CardWrapper title='Order Details'>
<div className='table'>
{Object.entries(details).map(([key, value], index) => (
<div className='row' key={index}>
<div className='cell'>
<Text size='sm' color='quill-typography__color--subtle'>
<Localize i18n_default_text={key} />
</Text>
</div>
<div className='cell'>
{Array.isArray(value) ? (
value.map((val, i) => (
<Text key={i} size='sm'>
{val}
</Text>
))
) : (
<Text size='sm'>{value as string | number}</Text>
)}
</div>
<div className='table'>
{Object.entries(details).map(([key, value], index) => (
<div className='row' key={index}>
<div className='cell'>
<Text size='sm' color='quill-typography__color--subtle'>
{key}
</Text>
</div>
))}
</div>
</CardWrapper>
<div className='cell'>
{Array.isArray(value) ? (
value.map((val, i) => (
<Text key={i} size='sm'>
{val}
</Text>
))
) : (
<Text size='sm'>{value as string | number}</Text>
)}
</div>
</div>
))}
</div>
</div>
);
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,38 +6,104 @@ import DealCancellationRemainingTime from '../DealCancellationRemainingTime/deal
import { observer } from '@deriv/stores';
import useContractDetails from 'AppV2/Hooks/useContractDetails';
import { CONTRACT_TYPES, isAccumulatorContract, isValidToCancel } from '@deriv/shared';
import { useTraderStore } from 'Stores/useTraderStores';

type RiskManagementItemProps = {
label: React.ReactNode;
modal_body_content: React.ReactNode;
validation_message?: React.ReactNode;
is_deal_cancellation?: boolean;
value?: number | null;
type?: string;
};

const RiskManagementItem = observer(
({ label, modal_body_content, validation_message, is_deal_cancellation = false }: RiskManagementItemProps) => {
const [toggle, setToggle] = React.useState(false);
const [isOpen, setIsOpen] = React.useState(false);
const dummy_boolean = false; // This will be flag from backend
const { has_take_profit } = useTraderStore();
const { contract_info } = useContractDetails();
({
label,
modal_body_content,
validation_message,
is_deal_cancellation = false,
value,
type,
}: RiskManagementItemProps) => {
const [toggle, setToggle] = React.useState(Boolean(value));
const [isSheetOpen, setIsSheetOpen] = React.useState(false);
const [isEnabled, setIsEnabled] = React.useState(false);
const dummy_boolean = false;
const [stepperValue, setStepperValue] = React.useState(0);
const { contract_info, contract } = useContractDetails();
const { contract_type, currency } = contract_info;
const { validation_errors, updateLimitOrder, clearContractUpdateConfigValues } = contract;
const is_valid_to_cancel = isValidToCancel(contract_info);
const is_accumulator = isAccumulatorContract(contract_type);

React.useEffect(() => {
if (value) {
setStepperValue(value);
setToggle(Boolean(value));
}
return () => clearContractUpdateConfigValues();
}, [clearContractUpdateConfigValues, value]);

const isDealCancellation = is_valid_to_cancel;
const finalValue = Math.abs(value as number);

const errorKey = `contract_update_${type}` as 'contract_update_stop_loss' | 'contract_update_take_profit';
const errorMessage = validation_errors[errorKey]?.length > 0 ? validation_errors[errorKey][0] : '';

const info_message = {
[CONTRACT_TYPES.ACCUMULATOR]: (
<Localize i18n_default_text='Take profit can’t be adjusted for ongoing accumulator contracts.' />
),
[CONTRACT_TYPES.MULTIPLIER.UP || CONTRACT_TYPES.MULTIPLIER.DOWN]:
[CONTRACT_TYPES.MULTIPLIER.UP]:
is_valid_to_cancel && !is_deal_cancellation ? (
<Localize i18n_default_text='Take profit and stop loss are unavailable while deal cancellation is enabled.' />
) : (
''
),
[CONTRACT_TYPES.MULTIPLIER.DOWN]:
is_valid_to_cancel && !is_deal_cancellation ? (
<Localize i18n_default_text='Take profit and stop loss are unavailable while deal cancellation is enabled.' />
) : (
''
),
} as const;

const onChange = (
e: React.ChangeEvent<HTMLInputElement> | { target: { name: string; value: number | string | boolean } }
) => {
const { value } = e.target;
setStepperValue(value as number);
contract.onChange?.({
name: `contract_update_${type}`,
value,
});
};

const handleToggleSwitch = (value: boolean) => {
clearContractUpdateConfigValues();
if (value) {
setIsSheetOpen(true);
setIsEnabled(true);
} else {
contract.onChange?.({
name: `has_contract_update_${type}`,
value,
});
updateLimitOrder();
setToggle(!toggle);
}
};

const onSave = () => {
if (isEnabled) {
contract.onChange?.({
name: `has_contract_update_${type}`,
value: true,
});
setIsEnabled(false);
}
updateLimitOrder();
};
return (
<div className='risk-management-item--container'>
<div className='risk-management-item'>
Expand All @@ -50,44 +116,68 @@ const RiskManagementItem = observer(
/>
</span>
{!is_deal_cancellation &&
(has_take_profit && is_accumulator ? (
<Text size='sm'>5 USD</Text>
(is_accumulator ? (
<Text size='sm'>
{finalValue} {currency}
</Text>
) : (
<ToggleSwitch checked={toggle} onChange={() => setToggle(!toggle)} />
<ToggleSwitch
disabled={isDealCancellation}
checked={toggle}
onChange={handleToggleSwitch}
/>
))}
{is_valid_to_cancel && is_deal_cancellation && <DealCancellationRemainingTime />}
</div>
{toggle && (
{!is_accumulator && toggle && (
<TextField
variant='fill'
inputSize='md'
disabled={isSheetOpen}
textAlignment='center'
value='5.00 USD'
onClick={() => setIsOpen(true)}
onFocus={() => setIsOpen(true)}
value={`${finalValue.toFixed(2)} ${currency}`}
onClick={() => {
clearContractUpdateConfigValues();
setStepperValue(finalValue);
setIsSheetOpen(true);
}}
onFocus={() => setIsSheetOpen(true)}
/>
)}
<ActionSheet.Root expandable isOpen={isOpen} onClose={() => setIsOpen(false)}>
<ActionSheet.Root
expandable
isOpen={isSheetOpen}
position='left'
onClose={() => {
setIsEnabled(false);
setIsSheetOpen(false);
}}
>
<ActionSheet.Portal>
<ActionSheet.Header title={label} />
<ActionSheet.Content>
<TextFieldWithSteppers
variant='fill'
inputSize='md'
textAlignment='center'
status='neutral'
unit={currency}
unitPlacement='right'
message={validation_message}
/>
{isSheetOpen && (
<TextFieldWithSteppers
variant='fill'
inputSize='md'
textAlignment='center'
status={errorMessage ? 'error' : 'neutral'}
name={type}
unit={currency}
value={Math.abs(stepperValue)}
onChange={onChange}
unitPlacement='right'
decimals={0}
message={errorMessage}
/>
)}
</ActionSheet.Content>
<ActionSheet.Footer
isPrimaryButtonDisabled={errorMessage !== ''}
shouldCloseOnPrimaryButtonClick
primaryAction={{
content: localize('Save'),
onAction: () => {
//do the save
},
onAction: onSave,
}}
/>
</ActionSheet.Portal>
Expand Down
3 changes: 3 additions & 0 deletions packages/trader/src/AppV2/Components/StopLoss/stop-loss.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import RiskManagementItem from '../RiskManagementItem';

const StopLoss = observer(() => {
const { contract_info } = useContractDetails();
const { limit_order } = contract_info;
const { is_stop_loss_visible } = getContractDetailsConfig(contract_info.contract_type ?? '');

return is_stop_loss_visible ? (
Expand All @@ -15,6 +16,8 @@ const StopLoss = observer(() => {
modal_body_content={
<Localize i18n_default_text='When your loss reaches or exceeds the set amount, your trade will be closed automatically.' />
}
value={limit_order?.stop_loss?.order_amount}
type='stop_loss'
validation_message='hello'
/>
) : null;
Expand Down
Loading

0 comments on commit 1804b43

Please sign in to comment.