@oanda/labs-spread-cost-calculator-widget 1.0.4 → 1.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +52 -0
- package/dist/main/SpreadCostCalculatorWidget/Main.js +6 -6
- package/dist/main/SpreadCostCalculatorWidget/Main.js.map +1 -1
- package/dist/main/SpreadCostCalculatorWidget/SpreadCostCalculatorWidget.js +25 -26
- package/dist/main/SpreadCostCalculatorWidget/SpreadCostCalculatorWidget.js.map +1 -1
- package/dist/main/SpreadCostCalculatorWidget/ValidationWrapper.js +3 -4
- package/dist/main/SpreadCostCalculatorWidget/ValidationWrapper.js.map +1 -1
- package/dist/main/SpreadCostCalculatorWidget/constant.js +2 -1
- package/dist/main/SpreadCostCalculatorWidget/constant.js.map +1 -1
- package/dist/main/SpreadCostCalculatorWidget/types.js.map +1 -1
- package/dist/main/SpreadCostCalculatorWidget/useCalculateSpread.js +9 -3
- package/dist/main/SpreadCostCalculatorWidget/useCalculateSpread.js.map +1 -1
- package/dist/main/SpreadCostCalculatorWidget/useInstrumentChange.js +5 -1
- package/dist/main/SpreadCostCalculatorWidget/useInstrumentChange.js.map +1 -1
- package/dist/main/SpreadCostCalculatorWidget/utils.js +2 -9
- package/dist/main/SpreadCostCalculatorWidget/utils.js.map +1 -1
- package/dist/module/SpreadCostCalculatorWidget/Main.js +8 -8
- package/dist/module/SpreadCostCalculatorWidget/Main.js.map +1 -1
- package/dist/module/SpreadCostCalculatorWidget/SpreadCostCalculatorWidget.js +26 -26
- package/dist/module/SpreadCostCalculatorWidget/SpreadCostCalculatorWidget.js.map +1 -1
- package/dist/module/SpreadCostCalculatorWidget/ValidationWrapper.js +3 -3
- package/dist/module/SpreadCostCalculatorWidget/ValidationWrapper.js.map +1 -1
- package/dist/module/SpreadCostCalculatorWidget/constant.js +1 -0
- package/dist/module/SpreadCostCalculatorWidget/constant.js.map +1 -1
- package/dist/module/SpreadCostCalculatorWidget/types.js.map +1 -1
- package/dist/module/SpreadCostCalculatorWidget/useCalculateSpread.js +9 -3
- package/dist/module/SpreadCostCalculatorWidget/useCalculateSpread.js.map +1 -1
- package/dist/module/SpreadCostCalculatorWidget/useInstrumentChange.js +5 -1
- package/dist/module/SpreadCostCalculatorWidget/useInstrumentChange.js.map +1 -1
- package/dist/module/SpreadCostCalculatorWidget/utils.js +2 -9
- package/dist/module/SpreadCostCalculatorWidget/utils.js.map +1 -1
- package/dist/types/SpreadCostCalculatorWidget/constant.d.ts +1 -0
- package/dist/types/SpreadCostCalculatorWidget/types.d.ts +2 -2
- package/dist/types/SpreadCostCalculatorWidget/useCalculateSpread.d.ts +2 -1
- package/dist/types/SpreadCostCalculatorWidget/useInstrumentChange.d.ts +1 -0
- package/dist/types/SpreadCostCalculatorWidget/utils.d.ts +1 -2
- package/package.json +3 -3
- package/src/SpreadCostCalculatorWidget/Main.tsx +6 -6
- package/src/SpreadCostCalculatorWidget/SpreadCostCalculatorWidget.tsx +28 -27
- package/src/SpreadCostCalculatorWidget/ValidationWrapper.tsx +3 -3
- package/src/SpreadCostCalculatorWidget/constant.ts +1 -0
- package/src/SpreadCostCalculatorWidget/types.ts +2 -5
- package/src/SpreadCostCalculatorWidget/useCalculateSpread.ts +14 -2
- package/src/SpreadCostCalculatorWidget/useInstrumentChange.ts +4 -0
- package/src/SpreadCostCalculatorWidget/utils.ts +2 -11
- package/test/SpreadCostCalculator.test.tsx +8 -3
- package/test/useCalculateSpread.test.tsx +15 -11
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
import React
|
|
2
|
-
import { ApolloClient,
|
|
3
|
-
import {
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { ApolloClient, InMemoryCache } from '@apollo/client';
|
|
3
|
+
import { WidgetProvider, WidgetWrapper } from '@oanda/labs-widget-common';
|
|
4
4
|
import { Division } from '@oanda/labs-live-rates-table-widget';
|
|
5
|
-
import { LocaleProvider } from '@oanda/mono-i18n';
|
|
6
5
|
import { translations } from '../translations';
|
|
7
6
|
import { ValidationWrapper } from './ValidationWrapper';
|
|
8
7
|
const SpreadCostCalculatorWidget = _ref => {
|
|
@@ -23,29 +22,30 @@ const SpreadCostCalculatorWidget = _ref => {
|
|
|
23
22
|
});
|
|
24
23
|
const divisionCode = division === Division.Opt ? Division.Ogm : division;
|
|
25
24
|
const dataSource = divisionCode === Division.Ogm ? 'MT5' : 'V20';
|
|
26
|
-
return React.createElement(
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
options: {
|
|
32
|
-
divisionCode,
|
|
33
|
-
dataSource
|
|
34
|
-
}
|
|
35
|
-
}, React.createElement(ApolloProvider, {
|
|
36
|
-
client: client
|
|
37
|
-
}, React.createElement(Suspense, null, React.createElement(ThemeProvider, {
|
|
25
|
+
return React.createElement(WidgetProvider, {
|
|
26
|
+
withSuspense: true,
|
|
27
|
+
locale: locale,
|
|
28
|
+
translations: translations,
|
|
29
|
+
client: client,
|
|
38
30
|
theme: theme,
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
31
|
+
styling: {
|
|
32
|
+
removePadding
|
|
33
|
+
},
|
|
34
|
+
liveRates: {
|
|
35
|
+
url: liveRatesUrl,
|
|
36
|
+
options: {
|
|
37
|
+
divisionCode,
|
|
38
|
+
dataSource
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}, React.createElement(WidgetWrapper, {
|
|
42
|
+
logoLink: logoLink,
|
|
43
|
+
linkArea: "logo"
|
|
44
|
+
}, React.createElement(ValidationWrapper, {
|
|
45
|
+
instruments: instruments,
|
|
46
|
+
division: division,
|
|
47
|
+
isParamError: isParamError
|
|
48
|
+
})));
|
|
49
49
|
};
|
|
50
50
|
export { SpreadCostCalculatorWidget };
|
|
51
51
|
//# sourceMappingURL=SpreadCostCalculatorWidget.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SpreadCostCalculatorWidget.js","names":["React","
|
|
1
|
+
{"version":3,"file":"SpreadCostCalculatorWidget.js","names":["React","ApolloClient","InMemoryCache","WidgetProvider","WidgetWrapper","Division","translations","ValidationWrapper","SpreadCostCalculatorWidget","_ref","graphqlUrl","liveRatesUrl","theme","locale","isParamError","removePadding","division","instruments","logoLink","client","uri","cache","divisionCode","Opt","Ogm","dataSource","createElement","withSuspense","styling","liveRates","url","options","linkArea"],"sources":["../../../src/SpreadCostCalculatorWidget/SpreadCostCalculatorWidget.tsx"],"sourcesContent":["import React, { FC } from 'react';\nimport { ApolloClient, InMemoryCache } from '@apollo/client';\nimport { WidgetProvider, WidgetWrapper } from '@oanda/labs-widget-common';\n\nimport { Division } from '@oanda/labs-live-rates-table-widget';\nimport { SpreadCostCalculatorWidgetConfig } from './types';\nimport { translations } from '../translations';\nimport { ValidationWrapper } from './ValidationWrapper';\n\nconst SpreadCostCalculatorWidget: FC<SpreadCostCalculatorWidgetConfig> = ({\n graphqlUrl,\n liveRatesUrl,\n theme,\n locale,\n isParamError,\n removePadding,\n division,\n instruments,\n logoLink,\n}) => {\n const client = new ApolloClient({\n uri: graphqlUrl,\n cache: new InMemoryCache(),\n });\n\n const divisionCode = division === Division.Opt ? Division.Ogm : division;\n const dataSource = divisionCode === Division.Ogm ? 'MT5' : 'V20';\n\n return (\n <WidgetProvider\n withSuspense\n locale={locale}\n translations={translations}\n client={client}\n theme={theme}\n styling={{\n removePadding,\n }}\n liveRates={{\n url: liveRatesUrl,\n options: { divisionCode, dataSource },\n }}\n >\n <WidgetWrapper\n logoLink={logoLink}\n linkArea=\"logo\"\n >\n <ValidationWrapper\n instruments={instruments}\n division={division}\n isParamError={isParamError}\n />\n </WidgetWrapper>\n </WidgetProvider>\n );\n};\n\nexport { SpreadCostCalculatorWidget };\n"],"mappings":"AAAA,OAAOA,KAAK,MAAc,OAAO;AACjC,SAASC,YAAY,EAAEC,aAAa,QAAQ,gBAAgB;AAC5D,SAASC,cAAc,EAAEC,aAAa,QAAQ,2BAA2B;AAEzE,SAASC,QAAQ,QAAQ,qCAAqC;AAE9D,SAASC,YAAY,QAAQ,iBAAiB;AAC9C,SAASC,iBAAiB,QAAQ,qBAAqB;AAEvD,MAAMC,0BAAgE,GAAGC,IAAA,IAUnE;EAAA,IAVoE;IACxEC,UAAU;IACVC,YAAY;IACZC,KAAK;IACLC,MAAM;IACNC,YAAY;IACZC,aAAa;IACbC,QAAQ;IACRC,WAAW;IACXC;EACF,CAAC,GAAAT,IAAA;EACC,MAAMU,MAAM,GAAG,IAAIlB,YAAY,CAAC;IAC9BmB,GAAG,EAAEV,UAAU;IACfW,KAAK,EAAE,IAAInB,aAAa,CAAC;EAC3B,CAAC,CAAC;EAEF,MAAMoB,YAAY,GAAGN,QAAQ,KAAKX,QAAQ,CAACkB,GAAG,GAAGlB,QAAQ,CAACmB,GAAG,GAAGR,QAAQ;EACxE,MAAMS,UAAU,GAAGH,YAAY,KAAKjB,QAAQ,CAACmB,GAAG,GAAG,KAAK,GAAG,KAAK;EAEhE,OACExB,KAAA,CAAA0B,aAAA,CAACvB,cAAc;IACbwB,YAAY;IACZd,MAAM,EAAEA,MAAO;IACfP,YAAY,EAAEA,YAAa;IAC3Ba,MAAM,EAAEA,MAAO;IACfP,KAAK,EAAEA,KAAM;IACbgB,OAAO,EAAE;MACPb;IACF,CAAE;IACFc,SAAS,EAAE;MACTC,GAAG,EAAEnB,YAAY;MACjBoB,OAAO,EAAE;QAAET,YAAY;QAAEG;MAAW;IACtC;EAAE,GAEFzB,KAAA,CAAA0B,aAAA,CAACtB,aAAa;IACZc,QAAQ,EAAEA,QAAS;IACnBc,QAAQ,EAAC;EAAM,GAEfhC,KAAA,CAAA0B,aAAA,CAACnB,iBAAiB;IAChBU,WAAW,EAAEA,WAAY;IACzBD,QAAQ,EAAEA,QAAS;IACnBF,YAAY,EAAEA;EAAa,CAC5B,CACY,CACD,CAAC;AAErB,CAAC;AAED,SAASN,0BAA0B","ignoreList":[]}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import React
|
|
1
|
+
import React from 'react';
|
|
2
2
|
import { useSuspenseQuery } from '@apollo/client';
|
|
3
|
-
import { ChartError,
|
|
3
|
+
import { ChartError, useLayoutProvider } from '@oanda/labs-widget-common';
|
|
4
4
|
import { Main } from './Main';
|
|
5
5
|
import { validateInstruments } from '../gql/validateInstruments';
|
|
6
6
|
const ValidationWrapper = _ref => {
|
|
@@ -11,7 +11,7 @@ const ValidationWrapper = _ref => {
|
|
|
11
11
|
} = _ref;
|
|
12
12
|
const {
|
|
13
13
|
size
|
|
14
|
-
} =
|
|
14
|
+
} = useLayoutProvider();
|
|
15
15
|
const {
|
|
16
16
|
data,
|
|
17
17
|
error
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ValidationWrapper.js","names":["React","
|
|
1
|
+
{"version":3,"file":"ValidationWrapper.js","names":["React","useSuspenseQuery","ChartError","useLayoutProvider","Main","validateInstruments","ValidationWrapper","_ref","division","instruments","isParamError","size","data","error","variables","fetchPolicy","errorPolicy","instrumentsData","mapInstrumentNames","map","instrument","name","displayName","showError","createElement","Fragment","className"],"sources":["../../../src/SpreadCostCalculatorWidget/ValidationWrapper.tsx"],"sourcesContent":["import React from 'react';\nimport { useSuspenseQuery } from '@apollo/client';\nimport { ChartError, useLayoutProvider } from '@oanda/labs-widget-common';\nimport { Main } from './Main';\nimport { validateInstruments } from '../gql/validateInstruments';\nimport { ValidateInstrumentsQuery, ValidateInstrumentsQueryVariables } from '../gql/types/graphql';\nimport { ValidationWrapperProps } from './types';\n\nconst ValidationWrapper = ({\n division,\n instruments,\n isParamError,\n}: ValidationWrapperProps) => {\n const { size } = useLayoutProvider();\n const { data, error } = useSuspenseQuery<\n ValidateInstrumentsQuery,\n ValidateInstrumentsQueryVariables\n >(validateInstruments, {\n variables: {\n instruments,\n division,\n },\n fetchPolicy: 'network-only',\n errorPolicy: 'all',\n });\n\n const instrumentsData = data?.mapInstrumentNames?.map((instrument) => ({\n name: instrument!.name,\n displayName: instrument!.displayName,\n })) || [];\n\n const showError = !!error || isParamError;\n\n return (\n <>\n {size && (\n <>\n {showError ? (\n <div className=\"lw-flex lw-h-[300px] lw-w-full lw-items-center lw-border lw-border-solid lw-border-border-primary\">\n <ChartError />\n </div>\n ) : (\n <Main instruments={instrumentsData} />\n )}\n </>\n )}\n </>\n );\n};\n\nexport { ValidationWrapper };\n"],"mappings":"AAAA,OAAOA,KAAK,MAAM,OAAO;AACzB,SAASC,gBAAgB,QAAQ,gBAAgB;AACjD,SAASC,UAAU,EAAEC,iBAAiB,QAAQ,2BAA2B;AACzE,SAASC,IAAI,QAAQ,QAAQ;AAC7B,SAASC,mBAAmB,QAAQ,4BAA4B;AAIhE,MAAMC,iBAAiB,GAAGC,IAAA,IAII;EAAA,IAJH;IACzBC,QAAQ;IACRC,WAAW;IACXC;EACsB,CAAC,GAAAH,IAAA;EACvB,MAAM;IAAEI;EAAK,CAAC,GAAGR,iBAAiB,CAAC,CAAC;EACpC,MAAM;IAAES,IAAI;IAAEC;EAAM,CAAC,GAAGZ,gBAAgB,CAGtCI,mBAAmB,EAAE;IACrBS,SAAS,EAAE;MACTL,WAAW;MACXD;IACF,CAAC;IACDO,WAAW,EAAE,cAAc;IAC3BC,WAAW,EAAE;EACf,CAAC,CAAC;EAEF,MAAMC,eAAe,GAAGL,IAAI,EAAEM,kBAAkB,EAAEC,GAAG,CAAEC,UAAU,KAAM;IACrEC,IAAI,EAAED,UAAU,CAAEC,IAAI;IACtBC,WAAW,EAAEF,UAAU,CAAEE;EAC3B,CAAC,CAAC,CAAC,IAAI,EAAE;EAET,MAAMC,SAAS,GAAG,CAAC,CAACV,KAAK,IAAIH,YAAY;EAEzC,OACEV,KAAA,CAAAwB,aAAA,CAAAxB,KAAA,CAAAyB,QAAA,QACGd,IAAI,IACLX,KAAA,CAAAwB,aAAA,CAAAxB,KAAA,CAAAyB,QAAA,QACGF,SAAS,GACRvB,KAAA,CAAAwB,aAAA;IAAKE,SAAS,EAAC;EAAmG,GAChH1B,KAAA,CAAAwB,aAAA,CAACtB,UAAU,MAAE,CACV,CAAC,GAENF,KAAA,CAAAwB,aAAA,CAACpB,IAAI;IAACK,WAAW,EAAEQ;EAAgB,CAAE,CAEvC,CAEF,CAAC;AAEP,CAAC;AAED,SAASX,iBAAiB","ignoreList":[]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"constant.js","names":["CELL_EMPTY_VALUE"],"sources":["../../../src/SpreadCostCalculatorWidget/constant.ts"],"sourcesContent":["export const CELL_EMPTY_VALUE = '\\u2014';\n"],"mappings":"AAAA,OAAO,MAAMA,gBAAgB,GAAG,QAAQ","ignoreList":[]}
|
|
1
|
+
{"version":3,"file":"constant.js","names":["CELL_EMPTY_VALUE","DEFAULT_CURRENCY"],"sources":["../../../src/SpreadCostCalculatorWidget/constant.ts"],"sourcesContent":["export const CELL_EMPTY_VALUE = '\\u2014';\nexport const DEFAULT_CURRENCY = 'USD';\n"],"mappings":"AAAA,OAAO,MAAMA,gBAAgB,GAAG,QAAQ;AACxC,OAAO,MAAMC,gBAAgB,GAAG,KAAK","ignoreList":[]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","names":["Locale"],"sources":["../../../src/SpreadCostCalculatorWidget/types.ts"],"sourcesContent":["import { WidgetConfig
|
|
1
|
+
{"version":3,"file":"types.js","names":["Locale"],"sources":["../../../src/SpreadCostCalculatorWidget/types.ts"],"sourcesContent":["import { WidgetConfig } from '@oanda/labs-widget-common';\nimport { Division } from '../gql/types/graphql';\n\nexport { Locale } from '@oanda/mono-i18n';\n\nexport type SpreadCostCalculatorWidgetConfig = WidgetConfig & {\n liveRatesUrl: string;\n division: Division;\n instruments: string[];\n};\n\nexport type InstrumentResponse = {\n name: string;\n displayName: string;\n};\n\nexport type MainProps = {\n instruments: InstrumentResponse[];\n};\n\nexport interface ValidationWrapperProps {\n division: Division;\n instruments: string[];\n isParamError?: boolean;\n}\n"],"mappings":"AAGA,SAASA,MAAM,QAAQ,kBAAkB","ignoreList":[]}
|
|
@@ -1,16 +1,22 @@
|
|
|
1
1
|
import { useDebounceValue } from 'usehooks-ts';
|
|
2
2
|
import { useEffect } from 'react';
|
|
3
|
+
import { numericFormatter } from 'react-number-format';
|
|
4
|
+
import { CELL_EMPTY_VALUE } from './constant';
|
|
3
5
|
const calculateAbsoluteSpreadCost = (unitsTraded, spread, pipLocation) => unitsTraded !== undefined && spread !== undefined && pipLocation !== undefined ? Math.ceil(unitsTraded * spread * Number((10 ** pipLocation).toFixed(Math.abs(pipLocation))) / 2 * 10000) / 10000 : undefined;
|
|
4
6
|
export const useCalculateSpread = _ref => {
|
|
5
7
|
let {
|
|
6
8
|
spread,
|
|
7
9
|
unitsTraded,
|
|
8
10
|
pipLocation,
|
|
9
|
-
delay = 350
|
|
11
|
+
delay = 350,
|
|
12
|
+
currency
|
|
10
13
|
} = _ref;
|
|
11
|
-
const [debouncedValue, setValue] = useDebounceValue(
|
|
14
|
+
const [debouncedValue, setValue] = useDebounceValue(CELL_EMPTY_VALUE, delay);
|
|
12
15
|
useEffect(() => {
|
|
13
|
-
|
|
16
|
+
const calculatedSpread = calculateAbsoluteSpreadCost(unitsTraded, spread, pipLocation);
|
|
17
|
+
setValue(calculatedSpread ? `${numericFormatter(calculatedSpread.toString(), {
|
|
18
|
+
thousandSeparator: ','
|
|
19
|
+
})} ${currency}` : CELL_EMPTY_VALUE);
|
|
14
20
|
}, [spread, unitsTraded, pipLocation, setValue]);
|
|
15
21
|
return debouncedValue;
|
|
16
22
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useCalculateSpread.js","names":["useDebounceValue","useEffect","calculateAbsoluteSpreadCost","unitsTraded","spread","pipLocation","undefined","Math","ceil","Number","toFixed","abs","useCalculateSpread","_ref","delay","debouncedValue","setValue"],"sources":["../../../src/SpreadCostCalculatorWidget/useCalculateSpread.ts"],"sourcesContent":["import { useDebounceValue } from 'usehooks-ts';\nimport { useEffect } from 'react';\nimport { Voidable } from '@oanda/labs-widget-common';\n\nexport type UseCalculateSpreadInput = {\n spread: Voidable<number>;\n unitsTraded: Voidable<number>;\n pipLocation: Voidable<number>;\n delay?: number;\n};\n\nconst calculateAbsoluteSpreadCost = (\n unitsTraded?: number,\n spread?: number,\n pipLocation?: number,\n): number | undefined => (unitsTraded !== undefined\n && spread !== undefined\n && pipLocation !== undefined\n ? Math.ceil(\n ((unitsTraded * spread * Number((10 ** pipLocation).toFixed(Math.abs(pipLocation)))) / 2)\n * 10000,\n ) / 10000\n : undefined);\n\nexport const useCalculateSpread = ({\n spread,\n unitsTraded,\n pipLocation,\n delay = 350,\n}: UseCalculateSpreadInput) => {\n const [debouncedValue, setValue] = useDebounceValue
|
|
1
|
+
{"version":3,"file":"useCalculateSpread.js","names":["useDebounceValue","useEffect","numericFormatter","CELL_EMPTY_VALUE","calculateAbsoluteSpreadCost","unitsTraded","spread","pipLocation","undefined","Math","ceil","Number","toFixed","abs","useCalculateSpread","_ref","delay","currency","debouncedValue","setValue","calculatedSpread","toString","thousandSeparator"],"sources":["../../../src/SpreadCostCalculatorWidget/useCalculateSpread.ts"],"sourcesContent":["import { useDebounceValue } from 'usehooks-ts';\nimport { useEffect } from 'react';\nimport { Voidable } from '@oanda/labs-widget-common';\nimport { numericFormatter } from 'react-number-format';\nimport { CELL_EMPTY_VALUE } from './constant';\n\nexport type UseCalculateSpreadInput = {\n spread: Voidable<number>;\n unitsTraded: Voidable<number>;\n pipLocation: Voidable<number>;\n delay?: number;\n currency: string;\n};\n\nconst calculateAbsoluteSpreadCost = (\n unitsTraded?: number,\n spread?: number,\n pipLocation?: number,\n): number | undefined => (unitsTraded !== undefined\n && spread !== undefined\n && pipLocation !== undefined\n ? Math.ceil(\n ((unitsTraded * spread * Number((10 ** pipLocation).toFixed(Math.abs(pipLocation)))) / 2)\n * 10000,\n ) / 10000\n : undefined);\n\nexport const useCalculateSpread = ({\n spread,\n unitsTraded,\n pipLocation,\n delay = 350,\n currency,\n}: UseCalculateSpreadInput) => {\n const [debouncedValue, setValue] = useDebounceValue(CELL_EMPTY_VALUE, delay);\n\n useEffect(() => {\n const calculatedSpread = calculateAbsoluteSpreadCost(unitsTraded, spread, pipLocation);\n setValue(\n calculatedSpread\n ? `${numericFormatter(calculatedSpread.toString(), {\n thousandSeparator: ',',\n })} ${currency}`\n : CELL_EMPTY_VALUE,\n );\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [spread, unitsTraded, pipLocation, setValue]);\n\n return debouncedValue;\n};\n"],"mappings":"AAAA,SAASA,gBAAgB,QAAQ,aAAa;AAC9C,SAASC,SAAS,QAAQ,OAAO;AAEjC,SAASC,gBAAgB,QAAQ,qBAAqB;AACtD,SAASC,gBAAgB,QAAQ,YAAY;AAU7C,MAAMC,2BAA2B,GAAGA,CAClCC,WAAoB,EACpBC,MAAe,EACfC,WAAoB,KACIF,WAAW,KAAKG,SAAS,IAC9CF,MAAM,KAAKE,SAAS,IACpBD,WAAW,KAAKC,SAAS,GAC1BC,IAAI,CAACC,IAAI,CACPL,WAAW,GAAGC,MAAM,GAAGK,MAAM,CAAC,CAAC,EAAE,IAAIJ,WAAW,EAAEK,OAAO,CAACH,IAAI,CAACI,GAAG,CAACN,WAAW,CAAC,CAAC,CAAC,GAAI,CAAC,GAChF,KACV,CAAC,GAAG,KAAK,GACPC,SAAU;AAEd,OAAO,MAAMM,kBAAkB,GAAGC,IAAA,IAMH;EAAA,IANI;IACjCT,MAAM;IACND,WAAW;IACXE,WAAW;IACXS,KAAK,GAAG,GAAG;IACXC;EACuB,CAAC,GAAAF,IAAA;EACxB,MAAM,CAACG,cAAc,EAAEC,QAAQ,CAAC,GAAGnB,gBAAgB,CAACG,gBAAgB,EAAEa,KAAK,CAAC;EAE5Ef,SAAS,CAAC,MAAM;IACd,MAAMmB,gBAAgB,GAAGhB,2BAA2B,CAACC,WAAW,EAAEC,MAAM,EAAEC,WAAW,CAAC;IACtFY,QAAQ,CACNC,gBAAgB,GACZ,GAAGlB,gBAAgB,CAACkB,gBAAgB,CAACC,QAAQ,CAAC,CAAC,EAAE;MACjDC,iBAAiB,EAAE;IACrB,CAAC,CAAC,IAAIL,QAAQ,EAAE,GACdd,gBACN,CAAC;EAEH,CAAC,EAAE,CAACG,MAAM,EAAED,WAAW,EAAEE,WAAW,EAAEY,QAAQ,CAAC,CAAC;EAEhD,OAAOD,cAAc;AACvB,CAAC","ignoreList":[]}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { useLiveRatesMessage, useLiveRatesQuery } from '@oanda/labs-widget-common';
|
|
2
2
|
import { useEffect, useState } from 'react';
|
|
3
|
+
import { getInstrumentCurrency } from './utils';
|
|
3
4
|
export const useInstrumentChange = _ref => {
|
|
4
5
|
let {
|
|
5
6
|
initialInstrument
|
|
@@ -13,6 +14,7 @@ export const useInstrumentChange = _ref => {
|
|
|
13
14
|
const [selectedInstrument, setSelectedInstrument] = useState(initialInstrument);
|
|
14
15
|
const [pipLocation, setPipLocation] = useState(undefined);
|
|
15
16
|
const [initialSpread, setSpread] = useState(undefined);
|
|
17
|
+
const [currency, setCurrency] = useState('');
|
|
16
18
|
const {
|
|
17
19
|
update,
|
|
18
20
|
error,
|
|
@@ -31,6 +33,7 @@ export const useInstrumentChange = _ref => {
|
|
|
31
33
|
setQuery({
|
|
32
34
|
instruments: [selectedInstrument.id]
|
|
33
35
|
});
|
|
36
|
+
setCurrency(getInstrumentCurrency(selectedInstrument.label));
|
|
34
37
|
}, [selectedInstrument.id]);
|
|
35
38
|
return {
|
|
36
39
|
selectedInstrument,
|
|
@@ -38,7 +41,8 @@ export const useInstrumentChange = _ref => {
|
|
|
38
41
|
pipLocation,
|
|
39
42
|
initialSpread,
|
|
40
43
|
loading,
|
|
41
|
-
error: !!error || !!connectionError
|
|
44
|
+
error: !!error || !!connectionError,
|
|
45
|
+
currency
|
|
42
46
|
};
|
|
43
47
|
};
|
|
44
48
|
//# sourceMappingURL=useInstrumentChange.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useInstrumentChange.js","names":["useLiveRatesMessage","useLiveRatesQuery","useEffect","useState","useInstrumentChange","_ref","initialInstrument","target","setQuery","closeQuery","loading","setLoading","selectedInstrument","setSelectedInstrument","pipLocation","setPipLocation","undefined","initialSpread","setSpread","update","error","connectionError","id","symbol","spread","instruments"],"sources":["../../../src/SpreadCostCalculatorWidget/useInstrumentChange.ts"],"sourcesContent":["import { SelectOption, useLiveRatesMessage, useLiveRatesQuery } from '@oanda/labs-widget-common';\nimport { useEffect, useState } from 'react';\n\nexport type UseInstrumentChangeInput = {\n initialInstrument: SelectOption;\n};\n\nexport const useInstrumentChange = ({\n initialInstrument,\n}: UseInstrumentChangeInput) => {\n const { target, setQuery, closeQuery } = useLiveRatesQuery();\n const [loading, setLoading] = useState(true);\n const [selectedInstrument, setSelectedInstrument] = useState(initialInstrument);\n const [pipLocation, setPipLocation] = useState<undefined | number>(undefined);\n const [initialSpread, setSpread] = useState<undefined | number>(undefined);\n\n const { update, error, connectionError } = useLiveRatesMessage(\n selectedInstrument.id,\n target,\n );\n\n useEffect(() => {\n if (selectedInstrument.id === update?.symbol) {\n setPipLocation(update.pipLocation);\n setSpread(update.spread);\n setLoading(false);\n closeQuery();\n }\n\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [update]);\n\n useEffect(() => {\n setLoading(true);\n setQuery({ instruments: [selectedInstrument.id] });\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [selectedInstrument.id]);\n\n return {\n selectedInstrument,\n setSelectedInstrument,\n pipLocation,\n initialSpread,\n loading,\n error: !!error || !!connectionError,\n };\n};\n"],"mappings":"AAAA,SAAuBA,mBAAmB,EAAEC,iBAAiB,QAAQ,2BAA2B;AAChG,SAASC,SAAS,EAAEC,QAAQ,QAAQ,OAAO;
|
|
1
|
+
{"version":3,"file":"useInstrumentChange.js","names":["useLiveRatesMessage","useLiveRatesQuery","useEffect","useState","getInstrumentCurrency","useInstrumentChange","_ref","initialInstrument","target","setQuery","closeQuery","loading","setLoading","selectedInstrument","setSelectedInstrument","pipLocation","setPipLocation","undefined","initialSpread","setSpread","currency","setCurrency","update","error","connectionError","id","symbol","spread","instruments","label"],"sources":["../../../src/SpreadCostCalculatorWidget/useInstrumentChange.ts"],"sourcesContent":["import { SelectOption, useLiveRatesMessage, useLiveRatesQuery } from '@oanda/labs-widget-common';\nimport { useEffect, useState } from 'react';\nimport { getInstrumentCurrency } from './utils';\n\nexport type UseInstrumentChangeInput = {\n initialInstrument: SelectOption;\n};\n\nexport const useInstrumentChange = ({\n initialInstrument,\n}: UseInstrumentChangeInput) => {\n const { target, setQuery, closeQuery } = useLiveRatesQuery();\n const [loading, setLoading] = useState(true);\n const [selectedInstrument, setSelectedInstrument] = useState(initialInstrument);\n const [pipLocation, setPipLocation] = useState<undefined | number>(undefined);\n const [initialSpread, setSpread] = useState<undefined | number>(undefined);\n const [currency, setCurrency] = useState('');\n\n const { update, error, connectionError } = useLiveRatesMessage(\n selectedInstrument.id,\n target,\n );\n\n useEffect(() => {\n if (selectedInstrument.id === update?.symbol) {\n setPipLocation(update.pipLocation);\n setSpread(update.spread);\n setLoading(false);\n closeQuery();\n }\n\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [update]);\n\n useEffect(() => {\n setLoading(true);\n setQuery({ instruments: [selectedInstrument.id] });\n setCurrency(getInstrumentCurrency(selectedInstrument.label));\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [selectedInstrument.id]);\n\n return {\n selectedInstrument,\n setSelectedInstrument,\n pipLocation,\n initialSpread,\n loading,\n error: !!error || !!connectionError,\n currency,\n };\n};\n"],"mappings":"AAAA,SAAuBA,mBAAmB,EAAEC,iBAAiB,QAAQ,2BAA2B;AAChG,SAASC,SAAS,EAAEC,QAAQ,QAAQ,OAAO;AAC3C,SAASC,qBAAqB,QAAQ,SAAS;AAM/C,OAAO,MAAMC,mBAAmB,GAAGC,IAAA,IAEH;EAAA,IAFI;IAClCC;EACwB,CAAC,GAAAD,IAAA;EACzB,MAAM;IAAEE,MAAM;IAAEC,QAAQ;IAAEC;EAAW,CAAC,GAAGT,iBAAiB,CAAC,CAAC;EAC5D,MAAM,CAACU,OAAO,EAAEC,UAAU,CAAC,GAAGT,QAAQ,CAAC,IAAI,CAAC;EAC5C,MAAM,CAACU,kBAAkB,EAAEC,qBAAqB,CAAC,GAAGX,QAAQ,CAACI,iBAAiB,CAAC;EAC/E,MAAM,CAACQ,WAAW,EAAEC,cAAc,CAAC,GAAGb,QAAQ,CAAqBc,SAAS,CAAC;EAC7E,MAAM,CAACC,aAAa,EAAEC,SAAS,CAAC,GAAGhB,QAAQ,CAAqBc,SAAS,CAAC;EAC1E,MAAM,CAACG,QAAQ,EAAEC,WAAW,CAAC,GAAGlB,QAAQ,CAAC,EAAE,CAAC;EAE5C,MAAM;IAAEmB,MAAM;IAAEC,KAAK;IAAEC;EAAgB,CAAC,GAAGxB,mBAAmB,CAC5Da,kBAAkB,CAACY,EAAE,EACrBjB,MACF,CAAC;EAEDN,SAAS,CAAC,MAAM;IACd,IAAIW,kBAAkB,CAACY,EAAE,KAAKH,MAAM,EAAEI,MAAM,EAAE;MAC5CV,cAAc,CAACM,MAAM,CAACP,WAAW,CAAC;MAClCI,SAAS,CAACG,MAAM,CAACK,MAAM,CAAC;MACxBf,UAAU,CAAC,KAAK,CAAC;MACjBF,UAAU,CAAC,CAAC;IACd;EAGF,CAAC,EAAE,CAACY,MAAM,CAAC,CAAC;EAEZpB,SAAS,CAAC,MAAM;IACdU,UAAU,CAAC,IAAI,CAAC;IAChBH,QAAQ,CAAC;MAAEmB,WAAW,EAAE,CAACf,kBAAkB,CAACY,EAAE;IAAE,CAAC,CAAC;IAClDJ,WAAW,CAACjB,qBAAqB,CAACS,kBAAkB,CAACgB,KAAK,CAAC,CAAC;EAE9D,CAAC,EAAE,CAAChB,kBAAkB,CAACY,EAAE,CAAC,CAAC;EAE3B,OAAO;IACLZ,kBAAkB;IAClBC,qBAAqB;IACrBC,WAAW;IACXG,aAAa;IACbP,OAAO;IACPY,KAAK,EAAE,CAAC,CAACA,KAAK,IAAI,CAAC,CAACC,eAAe;IACnCJ;EACF,CAAC;AACH,CAAC","ignoreList":[]}
|
|
@@ -1,10 +1,3 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
return instrument.split('_')[1] || ' ';
|
|
4
|
-
}
|
|
5
|
-
if (instrument?.name) {
|
|
6
|
-
return instrument.name.split('_')[1] || ' ';
|
|
7
|
-
}
|
|
8
|
-
return ' ';
|
|
9
|
-
};
|
|
1
|
+
import { DEFAULT_CURRENCY } from './constant';
|
|
2
|
+
export const getInstrumentCurrency = instrument => instrument.split('/')[1] || DEFAULT_CURRENCY;
|
|
10
3
|
//# sourceMappingURL=utils.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.js","names":["getInstrumentCurrency","instrument","split"
|
|
1
|
+
{"version":3,"file":"utils.js","names":["DEFAULT_CURRENCY","getInstrumentCurrency","instrument","split"],"sources":["../../../src/SpreadCostCalculatorWidget/utils.ts"],"sourcesContent":["import { DEFAULT_CURRENCY } from './constant';\n\nexport const getInstrumentCurrency = (instrument: string): string => instrument.split('/')[1] || DEFAULT_CURRENCY;\n"],"mappings":"AAAA,SAASA,gBAAgB,QAAQ,YAAY;AAE7C,OAAO,MAAMC,qBAAqB,GAAIC,UAAkB,IAAaA,UAAU,CAACC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAIH,gBAAgB","ignoreList":[]}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { WidgetConfig
|
|
1
|
+
import { WidgetConfig } from '@oanda/labs-widget-common';
|
|
2
2
|
import { Division } from '../gql/types/graphql';
|
|
3
3
|
export { Locale } from '@oanda/mono-i18n';
|
|
4
|
-
export type SpreadCostCalculatorWidgetConfig = WidgetConfig &
|
|
4
|
+
export type SpreadCostCalculatorWidgetConfig = WidgetConfig & {
|
|
5
5
|
liveRatesUrl: string;
|
|
6
6
|
division: Division;
|
|
7
7
|
instruments: string[];
|
|
@@ -4,5 +4,6 @@ export type UseCalculateSpreadInput = {
|
|
|
4
4
|
unitsTraded: Voidable<number>;
|
|
5
5
|
pipLocation: Voidable<number>;
|
|
6
6
|
delay?: number;
|
|
7
|
+
currency: string;
|
|
7
8
|
};
|
|
8
|
-
export declare const useCalculateSpread: ({ spread, unitsTraded, pipLocation, delay, }: UseCalculateSpreadInput) =>
|
|
9
|
+
export declare const useCalculateSpread: ({ spread, unitsTraded, pipLocation, delay, currency, }: UseCalculateSpreadInput) => string;
|
|
@@ -1,2 +1 @@
|
|
|
1
|
-
|
|
2
|
-
export declare const getInstrumentCurrency: (instrument: string | InstrumentResponse | null) => string;
|
|
1
|
+
export declare const getInstrumentCurrency: (instrument: string) => string;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@oanda/labs-spread-cost-calculator-widget",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.6",
|
|
4
4
|
"description": "Labs Spread Cost Calculator Widget",
|
|
5
5
|
"main": "dist/main/index.js",
|
|
6
6
|
"module": "dist/module/index.js",
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
"author": "OANDA",
|
|
13
13
|
"license": "UNLICENSED",
|
|
14
14
|
"dependencies": {
|
|
15
|
-
"@oanda/labs-widget-common": "^1.0.
|
|
15
|
+
"@oanda/labs-widget-common": "^1.0.173",
|
|
16
16
|
"@oanda/mono-i18n": "10.0.1",
|
|
17
17
|
"echarts": "5.5.0",
|
|
18
18
|
"echarts-for-react": "3.0.2",
|
|
@@ -22,5 +22,5 @@
|
|
|
22
22
|
"@graphql-codegen/cli": "5.0.0",
|
|
23
23
|
"@graphql-codegen/client-preset": "4.1.0"
|
|
24
24
|
},
|
|
25
|
-
"gitHead": "
|
|
25
|
+
"gitHead": "67a7801f99f0bab94dd6067a102761f51de786c1"
|
|
26
26
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React, {
|
|
2
|
-
FC,
|
|
2
|
+
FC, useEffect,
|
|
3
3
|
} from 'react';
|
|
4
4
|
import { useLocale } from '@oanda/mono-i18n';
|
|
5
5
|
import {
|
|
@@ -9,19 +9,17 @@ import {
|
|
|
9
9
|
NumberInput,
|
|
10
10
|
Select,
|
|
11
11
|
Size,
|
|
12
|
-
|
|
12
|
+
useLayoutProvider,
|
|
13
13
|
useNumberFormat,
|
|
14
14
|
} from '@oanda/labs-widget-common';
|
|
15
15
|
import { useCalculateSpread } from './useCalculateSpread';
|
|
16
|
-
import { getInstrumentCurrency } from './utils';
|
|
17
16
|
import { useInstrumentChange } from './useInstrumentChange';
|
|
18
17
|
import { MainProps } from './types';
|
|
19
|
-
import { CELL_EMPTY_VALUE } from './constant';
|
|
20
18
|
|
|
21
19
|
const Main: FC<MainProps> = ({
|
|
22
20
|
instruments,
|
|
23
21
|
}) => {
|
|
24
|
-
const { size } =
|
|
22
|
+
const { size } = useLayoutProvider();
|
|
25
23
|
const isDesktop = size === Size.DESKTOP;
|
|
26
24
|
|
|
27
25
|
const selectOptions = instruments.map((instrument) => ({
|
|
@@ -52,6 +50,7 @@ const Main: FC<MainProps> = ({
|
|
|
52
50
|
initialSpread,
|
|
53
51
|
loading,
|
|
54
52
|
error,
|
|
53
|
+
currency,
|
|
55
54
|
} = useInstrumentChange({
|
|
56
55
|
initialInstrument: {
|
|
57
56
|
id: instruments[0].name,
|
|
@@ -74,6 +73,7 @@ const Main: FC<MainProps> = ({
|
|
|
74
73
|
spread,
|
|
75
74
|
unitsTraded,
|
|
76
75
|
pipLocation,
|
|
76
|
+
currency,
|
|
77
77
|
});
|
|
78
78
|
|
|
79
79
|
return (
|
|
@@ -125,7 +125,7 @@ const Main: FC<MainProps> = ({
|
|
|
125
125
|
<div className="lw-pt-4 lw-text-text-primary">
|
|
126
126
|
<div>{lang('absolute_spread_cost')}</div>
|
|
127
127
|
<div className="lw-pt-2 lw-text-3xl lw-font-bold">
|
|
128
|
-
{spreadCost
|
|
128
|
+
{spreadCost}
|
|
129
129
|
</div>
|
|
130
130
|
</div>
|
|
131
131
|
</div>
|
|
@@ -1,10 +1,8 @@
|
|
|
1
|
-
import React, { FC
|
|
2
|
-
import { ApolloClient,
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
} from '@oanda/labs-widget-common';
|
|
1
|
+
import React, { FC } from 'react';
|
|
2
|
+
import { ApolloClient, InMemoryCache } from '@apollo/client';
|
|
3
|
+
import { WidgetProvider, WidgetWrapper } from '@oanda/labs-widget-common';
|
|
4
|
+
|
|
6
5
|
import { Division } from '@oanda/labs-live-rates-table-widget';
|
|
7
|
-
import { LocaleProvider } from '@oanda/mono-i18n';
|
|
8
6
|
import { SpreadCostCalculatorWidgetConfig } from './types';
|
|
9
7
|
import { translations } from '../translations';
|
|
10
8
|
import { ValidationWrapper } from './ValidationWrapper';
|
|
@@ -29,28 +27,31 @@ const SpreadCostCalculatorWidget: FC<SpreadCostCalculatorWidgetConfig> = ({
|
|
|
29
27
|
const dataSource = divisionCode === Division.Ogm ? 'MT5' : 'V20';
|
|
30
28
|
|
|
31
29
|
return (
|
|
32
|
-
<
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
30
|
+
<WidgetProvider
|
|
31
|
+
withSuspense
|
|
32
|
+
locale={locale}
|
|
33
|
+
translations={translations}
|
|
34
|
+
client={client}
|
|
35
|
+
theme={theme}
|
|
36
|
+
styling={{
|
|
37
|
+
removePadding,
|
|
38
|
+
}}
|
|
39
|
+
liveRates={{
|
|
40
|
+
url: liveRatesUrl,
|
|
41
|
+
options: { divisionCode, dataSource },
|
|
42
|
+
}}
|
|
43
|
+
>
|
|
44
|
+
<WidgetWrapper
|
|
45
|
+
logoLink={logoLink}
|
|
46
|
+
linkArea="logo"
|
|
36
47
|
>
|
|
37
|
-
<
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
isParamError={isParamError}
|
|
45
|
-
/>,
|
|
46
|
-
logoLink,
|
|
47
|
-
linkArea: 'logo',
|
|
48
|
-
})}
|
|
49
|
-
</ThemeProvider>
|
|
50
|
-
</Suspense>
|
|
51
|
-
</ApolloProvider>
|
|
52
|
-
</LiveRatesProvider>
|
|
53
|
-
</LocaleProvider>
|
|
48
|
+
<ValidationWrapper
|
|
49
|
+
instruments={instruments}
|
|
50
|
+
division={division}
|
|
51
|
+
isParamError={isParamError}
|
|
52
|
+
/>
|
|
53
|
+
</WidgetWrapper>
|
|
54
|
+
</WidgetProvider>
|
|
54
55
|
);
|
|
55
56
|
};
|
|
56
57
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import React
|
|
1
|
+
import React from 'react';
|
|
2
2
|
import { useSuspenseQuery } from '@apollo/client';
|
|
3
|
-
import { ChartError,
|
|
3
|
+
import { ChartError, useLayoutProvider } from '@oanda/labs-widget-common';
|
|
4
4
|
import { Main } from './Main';
|
|
5
5
|
import { validateInstruments } from '../gql/validateInstruments';
|
|
6
6
|
import { ValidateInstrumentsQuery, ValidateInstrumentsQueryVariables } from '../gql/types/graphql';
|
|
@@ -11,7 +11,7 @@ const ValidationWrapper = ({
|
|
|
11
11
|
instruments,
|
|
12
12
|
isParamError,
|
|
13
13
|
}: ValidationWrapperProps) => {
|
|
14
|
-
const { size } =
|
|
14
|
+
const { size } = useLayoutProvider();
|
|
15
15
|
const { data, error } = useSuspenseQuery<
|
|
16
16
|
ValidateInstrumentsQuery,
|
|
17
17
|
ValidateInstrumentsQueryVariables
|
|
@@ -1,12 +1,9 @@
|
|
|
1
|
-
import { WidgetConfig
|
|
1
|
+
import { WidgetConfig } from '@oanda/labs-widget-common';
|
|
2
2
|
import { Division } from '../gql/types/graphql';
|
|
3
3
|
|
|
4
4
|
export { Locale } from '@oanda/mono-i18n';
|
|
5
5
|
|
|
6
|
-
export type SpreadCostCalculatorWidgetConfig = WidgetConfig &
|
|
7
|
-
WidgetWrapperProps,
|
|
8
|
-
'removePadding'
|
|
9
|
-
> & {
|
|
6
|
+
export type SpreadCostCalculatorWidgetConfig = WidgetConfig & {
|
|
10
7
|
liveRatesUrl: string;
|
|
11
8
|
division: Division;
|
|
12
9
|
instruments: string[];
|
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
import { useDebounceValue } from 'usehooks-ts';
|
|
2
2
|
import { useEffect } from 'react';
|
|
3
3
|
import { Voidable } from '@oanda/labs-widget-common';
|
|
4
|
+
import { numericFormatter } from 'react-number-format';
|
|
5
|
+
import { CELL_EMPTY_VALUE } from './constant';
|
|
4
6
|
|
|
5
7
|
export type UseCalculateSpreadInput = {
|
|
6
8
|
spread: Voidable<number>;
|
|
7
9
|
unitsTraded: Voidable<number>;
|
|
8
10
|
pipLocation: Voidable<number>;
|
|
9
11
|
delay?: number;
|
|
12
|
+
currency: string;
|
|
10
13
|
};
|
|
11
14
|
|
|
12
15
|
const calculateAbsoluteSpreadCost = (
|
|
@@ -27,11 +30,20 @@ export const useCalculateSpread = ({
|
|
|
27
30
|
unitsTraded,
|
|
28
31
|
pipLocation,
|
|
29
32
|
delay = 350,
|
|
33
|
+
currency,
|
|
30
34
|
}: UseCalculateSpreadInput) => {
|
|
31
|
-
const [debouncedValue, setValue] = useDebounceValue
|
|
35
|
+
const [debouncedValue, setValue] = useDebounceValue(CELL_EMPTY_VALUE, delay);
|
|
32
36
|
|
|
33
37
|
useEffect(() => {
|
|
34
|
-
|
|
38
|
+
const calculatedSpread = calculateAbsoluteSpreadCost(unitsTraded, spread, pipLocation);
|
|
39
|
+
setValue(
|
|
40
|
+
calculatedSpread
|
|
41
|
+
? `${numericFormatter(calculatedSpread.toString(), {
|
|
42
|
+
thousandSeparator: ',',
|
|
43
|
+
})} ${currency}`
|
|
44
|
+
: CELL_EMPTY_VALUE,
|
|
45
|
+
);
|
|
46
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
35
47
|
}, [spread, unitsTraded, pipLocation, setValue]);
|
|
36
48
|
|
|
37
49
|
return debouncedValue;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { SelectOption, useLiveRatesMessage, useLiveRatesQuery } from '@oanda/labs-widget-common';
|
|
2
2
|
import { useEffect, useState } from 'react';
|
|
3
|
+
import { getInstrumentCurrency } from './utils';
|
|
3
4
|
|
|
4
5
|
export type UseInstrumentChangeInput = {
|
|
5
6
|
initialInstrument: SelectOption;
|
|
@@ -13,6 +14,7 @@ export const useInstrumentChange = ({
|
|
|
13
14
|
const [selectedInstrument, setSelectedInstrument] = useState(initialInstrument);
|
|
14
15
|
const [pipLocation, setPipLocation] = useState<undefined | number>(undefined);
|
|
15
16
|
const [initialSpread, setSpread] = useState<undefined | number>(undefined);
|
|
17
|
+
const [currency, setCurrency] = useState('');
|
|
16
18
|
|
|
17
19
|
const { update, error, connectionError } = useLiveRatesMessage(
|
|
18
20
|
selectedInstrument.id,
|
|
@@ -33,6 +35,7 @@ export const useInstrumentChange = ({
|
|
|
33
35
|
useEffect(() => {
|
|
34
36
|
setLoading(true);
|
|
35
37
|
setQuery({ instruments: [selectedInstrument.id] });
|
|
38
|
+
setCurrency(getInstrumentCurrency(selectedInstrument.label));
|
|
36
39
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
37
40
|
}, [selectedInstrument.id]);
|
|
38
41
|
|
|
@@ -43,5 +46,6 @@ export const useInstrumentChange = ({
|
|
|
43
46
|
initialSpread,
|
|
44
47
|
loading,
|
|
45
48
|
error: !!error || !!connectionError,
|
|
49
|
+
currency,
|
|
46
50
|
};
|
|
47
51
|
};
|
|
@@ -1,12 +1,3 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { DEFAULT_CURRENCY } from './constant';
|
|
2
2
|
|
|
3
|
-
export const getInstrumentCurrency = (instrument: string
|
|
4
|
-
if (typeof instrument === 'string') {
|
|
5
|
-
return instrument.split('_')[1] || ' ';
|
|
6
|
-
}
|
|
7
|
-
if (instrument?.name) {
|
|
8
|
-
return instrument.name.split('_')[1] || ' ';
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
return ' ';
|
|
12
|
-
};
|
|
3
|
+
export const getInstrumentCurrency = (instrument: string): string => instrument.split('/')[1] || DEFAULT_CURRENCY;
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
import React from 'react';
|
|
8
8
|
import { render } from '@testing-library/react';
|
|
9
|
+
import { LiveRatesProvider, MockLayoutProvider } from '@oanda/labs-widget-common';
|
|
9
10
|
import { Main } from '../src/SpreadCostCalculatorWidget/Main';
|
|
10
11
|
|
|
11
12
|
describe('Spread Cost Calculator', () => {
|
|
@@ -20,9 +21,13 @@ describe('Spread Cost Calculator', () => {
|
|
|
20
21
|
it('should render spread cost calculator component', async () => {
|
|
21
22
|
// When
|
|
22
23
|
const { findByTestId } = render(
|
|
23
|
-
<
|
|
24
|
-
|
|
25
|
-
|
|
24
|
+
<LiveRatesProvider url="oanda.com">
|
|
25
|
+
<MockLayoutProvider>
|
|
26
|
+
<Main
|
|
27
|
+
instruments={[{ name: 'EUR_USD', displayName: 'EUR/USD' }]}
|
|
28
|
+
/>
|
|
29
|
+
</MockLayoutProvider>
|
|
30
|
+
</LiveRatesProvider>,
|
|
26
31
|
);
|
|
27
32
|
|
|
28
33
|
// Then
|