Skip to content

Commit

Permalink
[BOT][Accumulators]maryia/bot-1980/feat: Adapt QS form as per new des…
Browse files Browse the repository at this point in the history
…ign (#17016)

* feat: Adapt QS form as per new design

* refactor: desktop form wrapper component

* refactor: desktop form wrapper component(2)

* fix: btn back on the desktop

* refactor: add useCallback for renderContent

* refactor: strategy list component

* fix: test cases of quick strategy

* refactor: change logic as per new configuration of QS

* add Stepper component from Quill, install quill libraries, update the version

* chore: add temp stepper.scss

* chore: merge master, resolve conflicts(part2)

* fix: UI Bugs while creating a quick strategy

* chore: update package-lock file

* fix: eslint issues

* style: fix margin strategy-template-picker

* fix: tablet version bugs and rtl

* fix: search option and change the color

* fix: tooltip text

* Delete packages/bot-web-ui/package-lock.json

* chore: remove server bot icons and parameters

---------

Co-authored-by: Sandeep Rajput <[email protected]>
  • Loading branch information
maryia-matskevich-deriv and sandeep-deriv authored Oct 23, 2024
1 parent 7905927 commit 2d1bbd7
Show file tree
Hide file tree
Showing 19 changed files with 995 additions and 41 deletions.
11 changes: 6 additions & 5 deletions packages/bot-web-ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -71,25 +71,27 @@
"webpack-cli": "^4.7.2"
},
"dependencies": {
"@deriv-com/quill-ui": "1.18.0",
"@deriv-com/ui": "1.36.4",
"@deriv/api": "^1.0.0",
"@deriv/api-types": "1.0.172",
"@deriv/bot-skeleton": "^1.0.0",
"@deriv/components": "^1.0.0",
"@deriv/hooks": "^1.0.0",
"@deriv/deriv-charts": "^2.5.1",
"@deriv/hooks": "^1.0.0",
"@deriv/quill-icons": "1.23.3",
"@deriv/shared": "^1.0.0",
"@deriv/stores": "^1.0.0",
"@deriv/translations": "^1.0.0",
"@deriv/quill-icons": "1.23.3",
"blockly": "^10.4.3",
"@testing-library/user-event": "^13.5.0",
"@types/react-router-dom": "^5.1.6",
"blockly": "^10.4.3",
"classnames": "^2.2.6",
"crc-32": "^1.2.0",
"dompurify": "^3.1.0",
"formik": "^2.1.4",
"gh-pages": "^6.1.1",
"html-react-parser": "5.1.12",
"immutable": "^3.8.2",
"lodash.debounce": "^4.0.8",
"lz-string": "^1.4.4",
Expand All @@ -105,7 +107,6 @@
"react-router-dom": "^5.2.0",
"react-toastify": "^9.1.3",
"react-transition-group": "4.4.2",
"html-react-parser": "5.1.12",
"yup": "^0.32.11"
}
}
}
1 change: 0 additions & 1 deletion packages/bot-web-ui/src/constants/bot-contents.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ export const DBOT_TABS: TDashboardTabIndex = Object.freeze({
BOT_BUILDER: 1,
CHART: 2,
TUTORIAL: 3,
SERVER_BOT: 4,
});

export const MAX_STRATEGIES = 10;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,21 @@ jest.mock('../config', () => ({
[],
],
},
D_ALEMBERT: {
label: 'D’Alembert',
},
OSCARS_GRIND: {
label: 'Oscar’s Grind',
},
REVERSE_MARTINGALE: {
label: 'Reverse Martingale',
},
REVERSE_D_ALEMBERT: {
label: 'Reverse D’Alembert',
},
STRATEGY_1_3_2_6: {
label: '1-3-2-6',
},
},
}));

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,8 @@ const SYMBOL: TConfigItem = {

const LABEL_TRADETYPE: TConfigItem = {
type: 'label',
label: localize('Trade type'),
description: localize('Your bot will use this trade type for every run'),
label: localize('Contract type'),
description: localize('Your bot will use this contract type for every run'),
};

const TRADETYPE: TConfigItem = {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,220 @@
import React from 'react';
import { useFormikContext } from 'formik';
import { Button, Text, ThemedScrollbars } from '@deriv/components';
import Icon from '@deriv/components/src/components/icon/icon';
import { observer } from '@deriv/stores';
import { localize } from '@deriv/translations';
import { useDBotStore } from 'Stores/useDBotStore';
import { rudderStackSendQsEditStrategyEvent } from '../../../../../analytics/rudderstack-quick-strategy';
import { STRATEGIES } from '../../config';
import { TFormData, TFormValues } from '../../types';
import StrategyTabContent from '../strategy-tab-content';
import useQsSubmitHandler from '../useQsSubmitHandler';
import QSStepper from './qs-stepper';
import StrategyTemplatePicker from './strategy-template-picker';
import { QsSteps } from './trade-constants';
import '../../quick-strategy.scss';

type TDesktopFormWrapper = {
children: React.ReactNode;
current_step: QsSteps;
setCurrentStep: (current_step: QsSteps) => void;
onClickClose: () => void;
selected_trade_type: string;
setSelectedTradeType: (selected_trade_type: string) => void;
};

const QuickSelectionPanel = ({
selected_trade_type,
selected_startegy_label,
children,
}: Pick<TDesktopFormWrapper, 'selected_trade_type' | 'children'> & { selected_startegy_label: string }) => (
<>
<div className='qs__selected-options'>
<div className='qs__selected-options__item'>
<Text size='xs' line_height='s'>
{localize('Trade type')}
</Text>
<Text size='xs' weight='bold' line_height='s'>
{selected_trade_type}
</Text>
</div>
<div className='qs__selected-options__item'>
<Text size='xs' line_height='s'>
{localize('Strategy')}
</Text>
<Text size='xs' weight='bold' line_height='s'>
{selected_startegy_label}
</Text>
</div>
</div>
<StrategyTabContent formfields={children} active_tab={'TRADE_PARAMETERS'} />
</>
);

const FormWrapper = observer(
({
children,
current_step,
setCurrentStep,
onClickClose,
selected_trade_type,
setSelectedTradeType,
}: TDesktopFormWrapper) => {
const scroll_ref = React.useRef<HTMLDivElement & SVGSVGElement>(null);
const { submitForm, isValid, setFieldValue, validateForm, values } = useFormikContext<TFormValues>();
const { quick_strategy } = useDBotStore();
const { selected_strategy, onSubmit, is_stop_bot_dialog_open } = quick_strategy;
const { handleSubmit } = useQsSubmitHandler();

const selected_startegy_label = STRATEGIES[selected_strategy as keyof typeof STRATEGIES].label;
const is_selected_strategy_step = current_step === QsSteps.StrategySelect;

React.useEffect(() => {
if (isValid && current_step === QsSteps.StrategyVerified) {
setCurrentStep(QsSteps.StrategyCompleted);
}
if (!isValid && current_step === QsSteps.StrategyCompleted) {
setCurrentStep(QsSteps.StrategyVerified);
}
}, [isValid, current_step]);

React.useEffect(() => {
validateForm();
}, [selected_strategy, validateForm]);

const onEdit = async () => {
await setFieldValue('action', 'EDIT');
validateForm();
submitForm().then((form_data: TFormData | void) => {
if (isValid && form_data) {
rudderStackSendQsEditStrategyEvent({
form_values: values,
selected_strategy,
});
onSubmit(form_data); // true to load and run the bot
}
});
};

const onRun = () => {
handleSubmit();
};

const onBack = () => {
setCurrentStep(QsSteps.StrategySelect);
};

const renderContent = React.useCallback(() => {
switch (current_step) {
case QsSteps.StrategySelect:
return (
<StrategyTemplatePicker
setCurrentStep={setCurrentStep}
setSelectedTradeType={setSelectedTradeType}
/>
);
case QsSteps.StrategyVerified:
return (
<QuickSelectionPanel
selected_trade_type={selected_trade_type}
selected_startegy_label={selected_startegy_label}
>
{children}
</QuickSelectionPanel>
);
case QsSteps.StrategyCompleted:
return (
<QuickSelectionPanel
selected_trade_type={selected_trade_type}
selected_startegy_label={selected_startegy_label}
>
{children}
</QuickSelectionPanel>
);
default:
return null;
}
}, [
current_step,
selected_trade_type,
selected_startegy_label,
children,
setCurrentStep,
setSelectedTradeType,
]);

return (
!is_stop_bot_dialog_open && (
<div className='qs'>
<div className='qs__head'>
<div className='qs__head__title'>
<Text weight='bold'>{localize('Quick Strategy')}</Text>
</div>
<div className='qs__head__action'>
<span
data-testid='qs-desktop-close-button'
onClick={onClickClose}
tabIndex={0}
onKeyDown={(e: React.KeyboardEvent) => {
if (e.key === 'Enter') {
onClickClose();
}
}}
>
<Icon icon='IcCross' />
</span>
</div>
</div>
<div className='qs__body'>
<div className='qs__body__sidebar'>
<div className='qs__body__sidebar__subtitle'>
<Text size='xs'>
{localize('Choose a template below and set your trade parameters.')}
</Text>
</div>
<QSStepper current_step={current_step} />
</div>
<div className='qs__body__content'>
<ThemedScrollbars
className='qs__form__container qs__form__container--no-footer'
autohide={false}
refSetter={scroll_ref}
>
{renderContent()}
</ThemedScrollbars>
{!is_selected_strategy_step && (
<div className='qs__body__content__footer'>
<Button
transparent
classNameSpan='qs__body__content__footer--back'
disabled={is_selected_strategy_step}
onClick={onBack}
>
{localize('Back')}
</Button>
<Button secondary disabled={!isValid} onClick={onEdit}>
{localize('Load')}
</Button>
<Button
data-testid='qs-run-button'
primary
onClick={e => {
e.preventDefault();
onRun();
}}
disabled={!isValid}
>
{localize('Run')}
</Button>
</div>
)}
</div>
</div>
</div>
)
);
}
);

export default React.memo(FormWrapper);
Loading

0 comments on commit 2d1bbd7

Please sign in to comment.