@oanda/labs-spread-cost-calculator-widget 1.0.6 → 1.0.8

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.
Files changed (84) hide show
  1. package/CHANGELOG.md +68 -0
  2. package/dist/main/SpreadCostCalculatorWidget/Main.js +23 -23
  3. package/dist/main/SpreadCostCalculatorWidget/Main.js.map +1 -1
  4. package/dist/main/SpreadCostCalculatorWidget/SpreadCostCalculatorWidget.js +12 -12
  5. package/dist/main/SpreadCostCalculatorWidget/SpreadCostCalculatorWidget.js.map +1 -1
  6. package/dist/main/SpreadCostCalculatorWidget/ValidationWrapper.js +5 -4
  7. package/dist/main/SpreadCostCalculatorWidget/ValidationWrapper.js.map +1 -1
  8. package/dist/main/SpreadCostCalculatorWidget/render.js +4 -4
  9. package/dist/main/SpreadCostCalculatorWidget/render.js.map +1 -1
  10. package/dist/main/SpreadCostCalculatorWidget/types.js.map +1 -1
  11. package/dist/main/SpreadCostCalculatorWidget/useCalculateSpread.js +3 -3
  12. package/dist/main/SpreadCostCalculatorWidget/useCalculateSpread.js.map +1 -1
  13. package/dist/main/SpreadCostCalculatorWidget/useInstrumentChange.js +1 -1
  14. package/dist/main/SpreadCostCalculatorWidget/useInstrumentChange.js.map +1 -1
  15. package/dist/main/SpreadCostCalculatorWidget/utils.js.map +1 -1
  16. package/dist/main/gql/types/fragment-masking.js +3 -2
  17. package/dist/main/gql/types/fragment-masking.js.map +1 -1
  18. package/dist/main/gql/types/gql.js +3 -2
  19. package/dist/main/gql/types/gql.js.map +1 -1
  20. package/dist/main/gql/types/graphql.js +71 -71
  21. package/dist/main/gql/types/graphql.js.map +1 -1
  22. package/dist/main/gql/types/index.js.map +1 -1
  23. package/dist/main/gql/validateInstruments.js +3 -8
  24. package/dist/main/gql/validateInstruments.js.map +1 -1
  25. package/dist/main/index.js +8 -8
  26. package/dist/main/index.js.map +1 -1
  27. package/dist/main/translations/index.js +1 -1
  28. package/dist/main/translations/index.js.map +1 -1
  29. package/dist/module/SpreadCostCalculatorWidget/Main.js +23 -23
  30. package/dist/module/SpreadCostCalculatorWidget/Main.js.map +1 -1
  31. package/dist/module/SpreadCostCalculatorWidget/SpreadCostCalculatorWidget.js +12 -12
  32. package/dist/module/SpreadCostCalculatorWidget/SpreadCostCalculatorWidget.js.map +1 -1
  33. package/dist/module/SpreadCostCalculatorWidget/ValidationWrapper.js +5 -4
  34. package/dist/module/SpreadCostCalculatorWidget/ValidationWrapper.js.map +1 -1
  35. package/dist/module/SpreadCostCalculatorWidget/render.js +4 -4
  36. package/dist/module/SpreadCostCalculatorWidget/render.js.map +1 -1
  37. package/dist/module/SpreadCostCalculatorWidget/types.js.map +1 -1
  38. package/dist/module/SpreadCostCalculatorWidget/useCalculateSpread.js +3 -3
  39. package/dist/module/SpreadCostCalculatorWidget/useCalculateSpread.js.map +1 -1
  40. package/dist/module/SpreadCostCalculatorWidget/useInstrumentChange.js +1 -1
  41. package/dist/module/SpreadCostCalculatorWidget/useInstrumentChange.js.map +1 -1
  42. package/dist/module/SpreadCostCalculatorWidget/utils.js.map +1 -1
  43. package/dist/module/gql/types/fragment-masking.js +3 -2
  44. package/dist/module/gql/types/fragment-masking.js.map +1 -1
  45. package/dist/module/gql/types/gql.js +3 -2
  46. package/dist/module/gql/types/gql.js.map +1 -1
  47. package/dist/module/gql/types/graphql.js +71 -71
  48. package/dist/module/gql/types/graphql.js.map +1 -1
  49. package/dist/module/gql/types/index.js +2 -2
  50. package/dist/module/gql/types/index.js.map +1 -1
  51. package/dist/module/gql/validateInstruments.js +3 -8
  52. package/dist/module/gql/validateInstruments.js.map +1 -1
  53. package/dist/module/index.js +1 -1
  54. package/dist/module/index.js.map +1 -1
  55. package/dist/module/translations/index.js +1 -1
  56. package/dist/module/translations/index.js.map +1 -1
  57. package/dist/types/SpreadCostCalculatorWidget/Main.d.ts +2 -2
  58. package/dist/types/SpreadCostCalculatorWidget/SpreadCostCalculatorWidget.d.ts +2 -2
  59. package/dist/types/SpreadCostCalculatorWidget/ValidationWrapper.d.ts +1 -1
  60. package/dist/types/SpreadCostCalculatorWidget/types.d.ts +6 -6
  61. package/dist/types/SpreadCostCalculatorWidget/useCalculateSpread.d.ts +3 -3
  62. package/dist/types/SpreadCostCalculatorWidget/useInstrumentChange.d.ts +3 -3
  63. package/dist/types/gql/types/gql.d.ts +2 -2
  64. package/dist/types/gql/types/index.d.ts +2 -2
  65. package/dist/types/index.d.ts +1 -1
  66. package/dist/types/translations/index.d.ts +2 -2
  67. package/package.json +3 -3
  68. package/src/SpreadCostCalculatorWidget/Main.tsx +32 -26
  69. package/src/SpreadCostCalculatorWidget/SpreadCostCalculatorWidget.tsx +12 -14
  70. package/src/SpreadCostCalculatorWidget/ValidationWrapper.tsx +24 -19
  71. package/src/SpreadCostCalculatorWidget/render.tsx +12 -12
  72. package/src/SpreadCostCalculatorWidget/types.ts +7 -6
  73. package/src/SpreadCostCalculatorWidget/useCalculateSpread.ts +25 -18
  74. package/src/SpreadCostCalculatorWidget/useInstrumentChange.ts +13 -7
  75. package/src/SpreadCostCalculatorWidget/utils.ts +2 -1
  76. package/src/gql/types/fragment-masking.ts +41 -21
  77. package/src/gql/types/gql.ts +7 -3
  78. package/src/gql/types/graphql.ts +126 -47
  79. package/src/gql/types/index.ts +2 -2
  80. package/src/index.ts +1 -1
  81. package/src/translations/index.ts +4 -4
  82. package/test/SpreadCostCalculator.test.tsx +8 -8
  83. package/test/useCalculateSpread.test.tsx +41 -34
  84. package/test/useInstrumentChange.test.tsx +11 -4
@@ -1,18 +1,18 @@
1
- import { WidgetConfig } from '@oanda/labs-widget-common';
2
- import { Division } from '../gql/types/graphql';
1
+ import type { WidgetConfig } from '@oanda/labs-widget-common';
2
+ import type { Division } from '../gql/types/graphql';
3
3
  export { Locale } from '@oanda/mono-i18n';
4
4
  export type SpreadCostCalculatorWidgetConfig = WidgetConfig & {
5
5
  liveRatesUrl: string;
6
6
  division: Division;
7
7
  instruments: string[];
8
8
  };
9
- export type InstrumentResponse = {
9
+ export interface InstrumentResponse {
10
10
  name: string;
11
11
  displayName: string;
12
- };
13
- export type MainProps = {
12
+ }
13
+ export interface MainProps {
14
14
  instruments: InstrumentResponse[];
15
- };
15
+ }
16
16
  export interface ValidationWrapperProps {
17
17
  division: Division;
18
18
  instruments: string[];
@@ -1,9 +1,9 @@
1
- import { Voidable } from '@oanda/labs-widget-common';
2
- export type UseCalculateSpreadInput = {
1
+ import type { Voidable } from '@oanda/labs-widget-common';
2
+ export interface UseCalculateSpreadInput {
3
3
  spread: Voidable<number>;
4
4
  unitsTraded: Voidable<number>;
5
5
  pipLocation: Voidable<number>;
6
6
  delay?: number;
7
7
  currency: string;
8
- };
8
+ }
9
9
  export declare const useCalculateSpread: ({ spread, unitsTraded, pipLocation, delay, currency, }: UseCalculateSpreadInput) => string;
@@ -1,7 +1,7 @@
1
- import { SelectOption } from '@oanda/labs-widget-common';
2
- export type UseInstrumentChangeInput = {
1
+ import type { SelectOption } from '@oanda/labs-widget-common';
2
+ export interface UseInstrumentChangeInput {
3
3
  initialInstrument: SelectOption;
4
- };
4
+ }
5
5
  export declare const useInstrumentChange: ({ initialInstrument, }: UseInstrumentChangeInput) => {
6
6
  selectedInstrument: SelectOption;
7
7
  setSelectedInstrument: import("react").Dispatch<import("react").SetStateAction<SelectOption>>;
@@ -11,7 +11,7 @@ import { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/
11
11
  * Therefore it is highly recommended to use the babel or swc plugin for production.
12
12
  */
13
13
  declare const documents: {
14
- "\n query validateInstruments($instruments: [String]!, $division: Division) {\n mapInstrumentNames(instruments: $instruments, division: $division) {\n name\n displayName\n }\n }\n": DocumentNode<types.ValidateInstrumentsQuery, types.Exact<{
14
+ '\n query validateInstruments($instruments: [String]!, $division: Division) {\n mapInstrumentNames(instruments: $instruments, division: $division) {\n name\n displayName\n }\n }\n': DocumentNode<types.ValidateInstrumentsQuery, types.Exact<{
15
15
  instruments: Array<types.InputMaybe<types.Scalars["String"]["input"]>> | types.InputMaybe<types.Scalars["String"]["input"]>;
16
16
  division?: types.InputMaybe<types.Division>;
17
17
  }>>;
@@ -32,6 +32,6 @@ export declare function graphql(source: string): unknown;
32
32
  /**
33
33
  * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
34
34
  */
35
- export declare function graphql(source: "\n query validateInstruments($instruments: [String]!, $division: Division) {\n mapInstrumentNames(instruments: $instruments, division: $division) {\n name\n displayName\n }\n }\n"): (typeof documents)["\n query validateInstruments($instruments: [String]!, $division: Division) {\n mapInstrumentNames(instruments: $instruments, division: $division) {\n name\n displayName\n }\n }\n"];
35
+ export declare function graphql(source: '\n query validateInstruments($instruments: [String]!, $division: Division) {\n mapInstrumentNames(instruments: $instruments, division: $division) {\n name\n displayName\n }\n }\n'): (typeof documents)['\n query validateInstruments($instruments: [String]!, $division: Division) {\n mapInstrumentNames(instruments: $instruments, division: $division) {\n name\n displayName\n }\n }\n'];
36
36
  export type DocumentType<TDocumentNode extends DocumentNode<any, any>> = TDocumentNode extends DocumentNode<infer TType, any> ? TType : never;
37
37
  export {};
@@ -1,2 +1,2 @@
1
- export * from "./fragment-masking";
2
- export * from "./gql";
1
+ export * from './fragment-masking';
2
+ export * from './gql';
@@ -1,2 +1,2 @@
1
- export * from './SpreadCostCalculatorWidget/types';
2
1
  export * from './SpreadCostCalculatorWidget/SpreadCostCalculatorWidget';
2
+ export * from './SpreadCostCalculatorWidget/types';
@@ -1,4 +1,4 @@
1
- import { Translations } from '@oanda/mono-i18n';
2
- import { defaultTranslations } from './translations';
1
+ import type { Translations } from '@oanda/mono-i18n';
2
+ import type { defaultTranslations } from './translations';
3
3
  export type TranslationKey = keyof typeof defaultTranslations;
4
4
  export declare const translations: Translations;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@oanda/labs-spread-cost-calculator-widget",
3
- "version": "1.0.6",
3
+ "version": "1.0.8",
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.173",
15
+ "@oanda/labs-widget-common": "^1.0.175",
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": "67a7801f99f0bab94dd6067a102761f51de786c1"
25
+ "gitHead": "ffe302e74b4bdf5fb28f1f7be09cfd2cb7672eb3"
26
26
  }
@@ -1,7 +1,3 @@
1
- import React, {
2
- FC, useEffect,
3
- } from 'react';
4
- import { useLocale } from '@oanda/mono-i18n';
5
1
  import {
6
2
  ChartError,
7
3
  cn,
@@ -12,13 +8,15 @@ import {
12
8
  useLayoutProvider,
13
9
  useNumberFormat,
14
10
  } from '@oanda/labs-widget-common';
11
+ import { useLocale } from '@oanda/mono-i18n';
12
+ import type { FC } from 'react';
13
+ import React, { useEffect } from 'react';
14
+
15
+ import type { MainProps } from './types';
15
16
  import { useCalculateSpread } from './useCalculateSpread';
16
17
  import { useInstrumentChange } from './useInstrumentChange';
17
- import { MainProps } from './types';
18
18
 
19
- const Main: FC<MainProps> = ({
20
- instruments,
21
- }) => {
19
+ const Main: FC<MainProps> = ({ instruments }) => {
22
20
  const { size } = useLayoutProvider();
23
21
  const isDesktop = size === Size.DESKTOP;
24
22
 
@@ -64,7 +62,7 @@ const Main: FC<MainProps> = ({
64
62
  formattedValue: initialSpread?.toString() || '',
65
63
  value: initialSpread?.toString() || '',
66
64
  });
67
- // eslint-disable-next-line react-hooks/exhaustive-deps
65
+ // eslint-disable-next-line react-hooks/exhaustive-deps
68
66
  }, [initialSpread]);
69
67
 
70
68
  const { lang } = useLocale();
@@ -84,42 +82,50 @@ const Main: FC<MainProps> = ({
84
82
  </div>
85
83
  ) : (
86
84
  <div
87
- data-testid="spread-cost-calculator"
88
85
  className="lw-mx-auto lw-flex lw-w-full lw-max-w-full lw-flex-col lw-content-center lw-justify-center lw-gap-8 lw-p-4"
86
+ data-testid="spread-cost-calculator"
89
87
  >
90
88
  <div className="lw-flex lw-flex-col lw-gap-2">
91
- <Label htmlFor={lang('instrument')} className="lw-text-text-primary">
89
+ <Label
90
+ className="lw-text-text-primary"
91
+ htmlFor={lang('instrument')}
92
+ >
92
93
  {lang('instrument')}
93
94
  </Label>
94
95
  <Select
95
- searchPlaceholder={lang('search')}
96
+ className="lw-grow-0"
97
+ maxHeight={isDesktop ? 190 : 220}
96
98
  options={selectOptions}
99
+ searchPlaceholder={lang('search')}
97
100
  selectedOption={selectedInstrument}
98
- className="lw-grow-0"
99
101
  setSelectedOption={setSelectedInstrument}
100
- maxHeight={isDesktop ? 190 : 220}
101
102
  />
102
103
  </div>
103
104
  <div className="lw-flex lw-max-w-full lw-flex-col lw-content-center lw-justify-center lw-gap-3">
104
- <div className={cn('lw-flex lw-max-w-full lw-flex-row lw-gap-3', !isDesktop && 'lw-flex-col lw-gap-8')}>
105
+ <div
106
+ className={cn(
107
+ 'lw-flex lw-max-w-full lw-flex-row lw-gap-3',
108
+ !isDesktop && 'lw-flex-col lw-gap-8'
109
+ )}
110
+ >
105
111
  <NumberInput
106
- onValueChange={onUnitChange}
107
- value={unitsTraded}
112
+ withoutArrows
113
+ disabled={loading}
108
114
  label={lang('units_traded')}
109
- onIncrement={incrementTradedUnits}
110
- onDecrement={decrementTradedUnits}
111
115
  placeholder={lang('volume')}
112
- disabled={loading}
113
- withoutArrows
116
+ value={unitsTraded}
117
+ onDecrement={decrementTradedUnits}
118
+ onIncrement={incrementTradedUnits}
119
+ onValueChange={onUnitChange}
114
120
  />
115
121
  <NumberInput
116
- onValueChange={onSpreadChange}
117
- value={spread}
122
+ disabled={loading}
118
123
  label={lang('spread')}
119
- onIncrement={incrementSpread}
120
- onDecrement={decrementSpread}
121
124
  placeholder={lang('pips')}
122
- disabled={loading}
125
+ value={spread}
126
+ onDecrement={decrementSpread}
127
+ onIncrement={incrementSpread}
128
+ onValueChange={onSpreadChange}
123
129
  />
124
130
  </div>
125
131
  <div className="lw-pt-4 lw-text-text-primary">
@@ -1,10 +1,11 @@
1
- import React, { FC } from 'react';
2
1
  import { ApolloClient, InMemoryCache } from '@apollo/client';
2
+ import { Division } from '@oanda/labs-live-rates-table-widget';
3
3
  import { WidgetProvider, WidgetWrapper } from '@oanda/labs-widget-common';
4
+ import type { FC } from 'react';
5
+ import React from 'react';
4
6
 
5
- import { Division } from '@oanda/labs-live-rates-table-widget';
6
- import { SpreadCostCalculatorWidgetConfig } from './types';
7
7
  import { translations } from '../translations';
8
+ import type { SpreadCostCalculatorWidgetConfig } from './types';
8
9
  import { ValidationWrapper } from './ValidationWrapper';
9
10
 
10
11
  const SpreadCostCalculatorWidget: FC<SpreadCostCalculatorWidgetConfig> = ({
@@ -29,25 +30,22 @@ const SpreadCostCalculatorWidget: FC<SpreadCostCalculatorWidgetConfig> = ({
29
30
  return (
30
31
  <WidgetProvider
31
32
  withSuspense
32
- locale={locale}
33
- translations={translations}
34
33
  client={client}
35
- theme={theme}
36
- styling={{
37
- removePadding,
38
- }}
39
34
  liveRates={{
40
35
  url: liveRatesUrl,
41
36
  options: { divisionCode, dataSource },
42
37
  }}
38
+ locale={locale}
39
+ styling={{
40
+ removePadding,
41
+ }}
42
+ theme={theme}
43
+ translations={translations}
43
44
  >
44
- <WidgetWrapper
45
- logoLink={logoLink}
46
- linkArea="logo"
47
- >
45
+ <WidgetWrapper linkArea="logo" logoLink={logoLink}>
48
46
  <ValidationWrapper
49
- instruments={instruments}
50
47
  division={division}
48
+ instruments={instruments}
51
49
  isParamError={isParamError}
52
50
  />
53
51
  </WidgetWrapper>
@@ -1,10 +1,14 @@
1
- import React from 'react';
2
1
  import { useSuspenseQuery } from '@apollo/client';
3
2
  import { ChartError, useLayoutProvider } from '@oanda/labs-widget-common';
4
- import { Main } from './Main';
3
+ import React from 'react';
4
+
5
+ import type {
6
+ ValidateInstrumentsQuery,
7
+ ValidateInstrumentsQueryVariables,
8
+ } from '../gql/types/graphql';
5
9
  import { validateInstruments } from '../gql/validateInstruments';
6
- import { ValidateInstrumentsQuery, ValidateInstrumentsQueryVariables } from '../gql/types/graphql';
7
- import { ValidationWrapperProps } from './types';
10
+ import { Main } from './Main';
11
+ import type { ValidationWrapperProps } from './types';
8
12
 
9
13
  const ValidationWrapper = ({
10
14
  division,
@@ -13,8 +17,8 @@ const ValidationWrapper = ({
13
17
  }: ValidationWrapperProps) => {
14
18
  const { size } = useLayoutProvider();
15
19
  const { data, error } = useSuspenseQuery<
16
- ValidateInstrumentsQuery,
17
- ValidateInstrumentsQueryVariables
20
+ ValidateInstrumentsQuery,
21
+ ValidateInstrumentsQueryVariables
18
22
  >(validateInstruments, {
19
23
  variables: {
20
24
  instruments,
@@ -24,25 +28,26 @@ const ValidationWrapper = ({
24
28
  errorPolicy: 'all',
25
29
  });
26
30
 
27
- const instrumentsData = data?.mapInstrumentNames?.map((instrument) => ({
28
- name: instrument!.name,
29
- displayName: instrument!.displayName,
30
- })) || [];
31
+ const instrumentsData =
32
+ data?.mapInstrumentNames?.map((instrument) => ({
33
+ name: instrument!.name,
34
+ displayName: instrument!.displayName,
35
+ })) || [];
31
36
 
32
37
  const showError = !!error || isParamError;
33
38
 
34
39
  return (
35
40
  <>
36
41
  {size && (
37
- <>
38
- {showError ? (
39
- <div className="lw-flex lw-h-[300px] lw-w-full lw-items-center lw-border lw-border-solid lw-border-border-primary">
40
- <ChartError />
41
- </div>
42
- ) : (
43
- <Main instruments={instrumentsData} />
44
- )}
45
- </>
42
+ <>
43
+ {showError ? (
44
+ <div className="lw-flex lw-h-[300px] lw-w-full lw-items-center lw-border lw-border-solid lw-border-border-primary">
45
+ <ChartError />
46
+ </div>
47
+ ) : (
48
+ <Main instruments={instrumentsData} />
49
+ )}
50
+ </>
46
51
  )}
47
52
  </>
48
53
  );
@@ -1,14 +1,13 @@
1
+ import type { Theme } from '@oanda/labs-widget-common';
2
+ import { validateLocale, validateToolParams } from '@oanda/labs-widget-common';
1
3
  import React from 'react';
2
4
  import { createRoot } from 'react-dom/client';
3
- import { Theme, validateLocale, validateToolParams } from '@oanda/labs-widget-common';
5
+
4
6
  import { SpreadCostCalculatorWidget } from './SpreadCostCalculatorWidget';
5
7
 
6
- const {
7
- graphqlUrl,
8
- liveRatesUrl,
9
- } = window.widgetsConfig || {};
8
+ const { graphqlUrl, liveRatesUrl } = window.widgetsConfig || {};
10
9
  const spreadCostCalculatorParamsElements = document.querySelectorAll(
11
- 'div[data-spread-cost-calculator-params]',
10
+ 'div[data-spread-cost-calculator-params]'
12
11
  );
13
12
 
14
13
  spreadCostCalculatorParamsElements.forEach((element) => {
@@ -28,7 +27,7 @@ spreadCostCalculatorParamsElements.forEach((element) => {
28
27
  [
29
28
  {
30
29
  name: 'locale',
31
- valueCheck: (value) => validateLocale(value),
30
+ valueCheck: (value: string | undefined) => validateLocale(value),
32
31
  },
33
32
  {
34
33
  name: 'graphqlUrl',
@@ -41,20 +40,21 @@ spreadCostCalculatorParamsElements.forEach((element) => {
41
40
  },
42
41
  {
43
42
  name: 'instruments',
44
- valueCheck: (value) => (value as string[]).length > 0 && (value as string[]).length <= 10,
43
+ valueCheck: (value) =>
44
+ (value as string[]).length > 0 && (value as string[]).length <= 10,
45
45
  },
46
- ],
46
+ ]
47
47
  );
48
48
 
49
49
  root.render(
50
50
  <SpreadCostCalculatorWidget
51
51
  division={division}
52
+ graphqlUrl={graphqlUrl}
52
53
  instruments={instruments}
54
+ isParamError={isParamError}
53
55
  liveRatesUrl={liveRatesUrl}
54
- graphqlUrl={graphqlUrl}
55
56
  locale={locale}
56
57
  theme={mode as Theme}
57
- isParamError={isParamError}
58
- />,
58
+ />
59
59
  );
60
60
  });
@@ -1,5 +1,6 @@
1
- import { WidgetConfig } from '@oanda/labs-widget-common';
2
- import { Division } from '../gql/types/graphql';
1
+ import type { WidgetConfig } from '@oanda/labs-widget-common';
2
+
3
+ import type { Division } from '../gql/types/graphql';
3
4
 
4
5
  export { Locale } from '@oanda/mono-i18n';
5
6
 
@@ -9,14 +10,14 @@ export type SpreadCostCalculatorWidgetConfig = WidgetConfig & {
9
10
  instruments: string[];
10
11
  };
11
12
 
12
- export type InstrumentResponse = {
13
+ export interface InstrumentResponse {
13
14
  name: string;
14
15
  displayName: string;
15
- };
16
+ }
16
17
 
17
- export type MainProps = {
18
+ export interface MainProps {
18
19
  instruments: InstrumentResponse[];
19
- };
20
+ }
20
21
 
21
22
  export interface ValidationWrapperProps {
22
23
  division: Division;
@@ -1,29 +1,32 @@
1
- import { useDebounceValue } from 'usehooks-ts';
1
+ import type { Voidable } from '@oanda/labs-widget-common';
2
2
  import { useEffect } from 'react';
3
- import { Voidable } from '@oanda/labs-widget-common';
4
3
  import { numericFormatter } from 'react-number-format';
4
+ import { useDebounceValue } from 'usehooks-ts';
5
+
5
6
  import { CELL_EMPTY_VALUE } from './constant';
6
7
 
7
- export type UseCalculateSpreadInput = {
8
+ export interface UseCalculateSpreadInput {
8
9
  spread: Voidable<number>;
9
10
  unitsTraded: Voidable<number>;
10
11
  pipLocation: Voidable<number>;
11
12
  delay?: number;
12
13
  currency: string;
13
- };
14
+ }
14
15
 
15
16
  const calculateAbsoluteSpreadCost = (
16
17
  unitsTraded?: number,
17
18
  spread?: number,
18
- pipLocation?: number,
19
- ): number | undefined => (unitsTraded !== undefined
20
- && spread !== undefined
21
- && pipLocation !== undefined
22
- ? Math.ceil(
23
- ((unitsTraded * spread * Number((10 ** pipLocation).toFixed(Math.abs(pipLocation)))) / 2)
24
- * 10000,
25
- ) / 10000
26
- : undefined);
19
+ pipLocation?: number
20
+ ): number | undefined =>
21
+ unitsTraded !== undefined && spread !== undefined && pipLocation !== undefined
22
+ ? Math.ceil(
23
+ ((unitsTraded *
24
+ spread *
25
+ Number((10 ** pipLocation).toFixed(Math.abs(pipLocation)))) /
26
+ 2) *
27
+ 10000
28
+ ) / 10000
29
+ : undefined;
27
30
 
28
31
  export const useCalculateSpread = ({
29
32
  spread,
@@ -35,15 +38,19 @@ export const useCalculateSpread = ({
35
38
  const [debouncedValue, setValue] = useDebounceValue(CELL_EMPTY_VALUE, delay);
36
39
 
37
40
  useEffect(() => {
38
- const calculatedSpread = calculateAbsoluteSpreadCost(unitsTraded, spread, pipLocation);
41
+ const calculatedSpread = calculateAbsoluteSpreadCost(
42
+ unitsTraded,
43
+ spread,
44
+ pipLocation
45
+ );
39
46
  setValue(
40
47
  calculatedSpread
41
48
  ? `${numericFormatter(calculatedSpread.toString(), {
42
- thousandSeparator: ',',
43
- })} ${currency}`
44
- : CELL_EMPTY_VALUE,
49
+ thousandSeparator: ',',
50
+ })} ${currency}`
51
+ : CELL_EMPTY_VALUE
45
52
  );
46
- // eslint-disable-next-line react-hooks/exhaustive-deps
53
+ // eslint-disable-next-line react-hooks/exhaustive-deps
47
54
  }, [spread, unitsTraded, pipLocation, setValue]);
48
55
 
49
56
  return debouncedValue;
@@ -1,24 +1,30 @@
1
- import { SelectOption, useLiveRatesMessage, useLiveRatesQuery } from '@oanda/labs-widget-common';
1
+ import type { SelectOption } from '@oanda/labs-widget-common';
2
+ import {
3
+ useLiveRatesMessage,
4
+ useLiveRatesQuery,
5
+ } from '@oanda/labs-widget-common';
2
6
  import { useEffect, useState } from 'react';
7
+
3
8
  import { getInstrumentCurrency } from './utils';
4
9
 
5
- export type UseInstrumentChangeInput = {
10
+ export interface UseInstrumentChangeInput {
6
11
  initialInstrument: SelectOption;
7
- };
12
+ }
8
13
 
9
14
  export const useInstrumentChange = ({
10
15
  initialInstrument,
11
16
  }: UseInstrumentChangeInput) => {
12
17
  const { target, setQuery, closeQuery } = useLiveRatesQuery();
13
18
  const [loading, setLoading] = useState(true);
14
- const [selectedInstrument, setSelectedInstrument] = useState(initialInstrument);
19
+ const [selectedInstrument, setSelectedInstrument] =
20
+ useState(initialInstrument);
15
21
  const [pipLocation, setPipLocation] = useState<undefined | number>(undefined);
16
22
  const [initialSpread, setSpread] = useState<undefined | number>(undefined);
17
23
  const [currency, setCurrency] = useState('');
18
24
 
19
25
  const { update, error, connectionError } = useLiveRatesMessage(
20
26
  selectedInstrument.id,
21
- target,
27
+ target
22
28
  );
23
29
 
24
30
  useEffect(() => {
@@ -29,14 +35,14 @@ export const useInstrumentChange = ({
29
35
  closeQuery();
30
36
  }
31
37
 
32
- // eslint-disable-next-line react-hooks/exhaustive-deps
38
+ // eslint-disable-next-line react-hooks/exhaustive-deps
33
39
  }, [update]);
34
40
 
35
41
  useEffect(() => {
36
42
  setLoading(true);
37
43
  setQuery({ instruments: [selectedInstrument.id] });
38
44
  setCurrency(getInstrumentCurrency(selectedInstrument.label));
39
- // eslint-disable-next-line react-hooks/exhaustive-deps
45
+ // eslint-disable-next-line react-hooks/exhaustive-deps
40
46
  }, [selectedInstrument.id]);
41
47
 
42
48
  return {
@@ -1,3 +1,4 @@
1
1
  import { DEFAULT_CURRENCY } from './constant';
2
2
 
3
- export const getInstrumentCurrency = (instrument: string): string => instrument.split('/')[1] || DEFAULT_CURRENCY;
3
+ export const getInstrumentCurrency = (instrument: string): string =>
4
+ instrument.split('/')[1] || DEFAULT_CURRENCY;
@@ -1,18 +1,21 @@
1
- import { ResultOf, DocumentTypeDecoration, TypedDocumentNode } from '@graphql-typed-document-node/core';
1
+ import {
2
+ ResultOf,
3
+ DocumentTypeDecoration,
4
+ TypedDocumentNode,
5
+ } from '@graphql-typed-document-node/core';
2
6
  import { FragmentDefinitionNode } from 'graphql';
3
7
  import { Incremental } from './graphql';
4
8
 
5
-
6
- export type FragmentType<TDocumentType extends DocumentTypeDecoration<any, any>> = TDocumentType extends DocumentTypeDecoration<
7
- infer TType,
8
- any
9
- >
10
- ? [TType] extends [{ ' $fragmentName'?: infer TKey }]
11
- ? TKey extends string
12
- ? { ' $fragmentRefs'?: { [key in TKey]: TType } }
9
+ export type FragmentType<
10
+ TDocumentType extends DocumentTypeDecoration<any, any>,
11
+ > =
12
+ TDocumentType extends DocumentTypeDecoration<infer TType, any>
13
+ ? [TType] extends [{ ' $fragmentName'?: infer TKey }]
14
+ ? TKey extends string
15
+ ? { ' $fragmentRefs'?: { [key in TKey]: TType } }
16
+ : never
13
17
  : never
14
- : never
15
- : never;
18
+ : never;
16
19
 
17
20
  // return non-nullable if `fragmentType` is non-nullable
18
21
  export function useFragment<TType>(
@@ -22,7 +25,10 @@ export function useFragment<TType>(
22
25
  // return nullable if `fragmentType` is nullable
23
26
  export function useFragment<TType>(
24
27
  _documentNode: DocumentTypeDecoration<TType, any>,
25
- fragmentType: FragmentType<DocumentTypeDecoration<TType, any>> | null | undefined
28
+ fragmentType:
29
+ | FragmentType<DocumentTypeDecoration<TType, any>>
30
+ | null
31
+ | undefined
26
32
  ): TType | null | undefined;
27
33
  // return array of non-nullable if `fragmentType` is array of non-nullable
28
34
  export function useFragment<TType>(
@@ -32,35 +38,49 @@ export function useFragment<TType>(
32
38
  // return array of nullable if `fragmentType` is array of nullable
33
39
  export function useFragment<TType>(
34
40
  _documentNode: DocumentTypeDecoration<TType, any>,
35
- fragmentType: ReadonlyArray<FragmentType<DocumentTypeDecoration<TType, any>>> | null | undefined
41
+ fragmentType:
42
+ | ReadonlyArray<FragmentType<DocumentTypeDecoration<TType, any>>>
43
+ | null
44
+ | undefined
36
45
  ): ReadonlyArray<TType> | null | undefined;
37
46
  export function useFragment<TType>(
38
47
  _documentNode: DocumentTypeDecoration<TType, any>,
39
- fragmentType: FragmentType<DocumentTypeDecoration<TType, any>> | ReadonlyArray<FragmentType<DocumentTypeDecoration<TType, any>>> | null | undefined
48
+ fragmentType:
49
+ | FragmentType<DocumentTypeDecoration<TType, any>>
50
+ | ReadonlyArray<FragmentType<DocumentTypeDecoration<TType, any>>>
51
+ | null
52
+ | undefined
40
53
  ): TType | ReadonlyArray<TType> | null | undefined {
41
54
  return fragmentType as any;
42
55
  }
43
56
 
44
-
45
57
  export function makeFragmentData<
46
58
  F extends DocumentTypeDecoration<any, any>,
47
- FT extends ResultOf<F>
59
+ FT extends ResultOf<F>,
48
60
  >(data: FT, _fragment: F): FragmentType<F> {
49
61
  return data as FragmentType<F>;
50
62
  }
51
63
  export function isFragmentReady<TQuery, TFrag>(
52
64
  queryNode: DocumentTypeDecoration<TQuery, any>,
53
65
  fragmentNode: TypedDocumentNode<TFrag>,
54
- data: FragmentType<TypedDocumentNode<Incremental<TFrag>, any>> | null | undefined
66
+ data:
67
+ | FragmentType<TypedDocumentNode<Incremental<TFrag>, any>>
68
+ | null
69
+ | undefined
55
70
  ): data is FragmentType<typeof fragmentNode> {
56
- const deferredFields = (queryNode as { __meta__?: { deferredFields: Record<string, (keyof TFrag)[]> } }).__meta__
57
- ?.deferredFields;
71
+ const deferredFields = (
72
+ queryNode as {
73
+ __meta__?: { deferredFields: Record<string, (keyof TFrag)[]> };
74
+ }
75
+ ).__meta__?.deferredFields;
58
76
 
59
77
  if (!deferredFields) return true;
60
78
 
61
- const fragDef = fragmentNode.definitions[0] as FragmentDefinitionNode | undefined;
79
+ const fragDef = fragmentNode.definitions[0] as
80
+ | FragmentDefinitionNode
81
+ | undefined;
62
82
  const fragName = fragDef?.name?.value;
63
83
 
64
84
  const fields = (fragName && deferredFields[fragName]) || [];
65
- return fields.length > 0 && fields.every(field => data && field in data);
85
+ return fields.length > 0 && fields.every((field) => data && field in data);
66
86
  }