@transferwise/components 46.3.0 → 46.5.0

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 (41) hide show
  1. package/build/index.esm.js +119 -127
  2. package/build/index.esm.js.map +1 -1
  3. package/build/index.js +119 -127
  4. package/build/index.js.map +1 -1
  5. package/build/types/common/responsivePanel/ResponsivePanel.d.ts.map +1 -1
  6. package/build/types/dimmer/Dimmer.d.ts.map +1 -1
  7. package/build/types/index.d.ts +1 -0
  8. package/build/types/index.d.ts.map +1 -1
  9. package/build/types/inputs/SelectInput.d.ts +2 -2
  10. package/build/types/inputs/SelectInput.d.ts.map +1 -1
  11. package/build/types/inputs/_BottomSheet.d.ts.map +1 -1
  12. package/build/types/inputs/_Popover.d.ts.map +1 -1
  13. package/build/types/moneyInput/MoneyInput.d.ts +45 -31
  14. package/build/types/moneyInput/MoneyInput.d.ts.map +1 -1
  15. package/build/types/moneyInput/MoneyInput.messages.d.ts +6 -6
  16. package/build/types/moneyInput/MoneyInput.messages.d.ts.map +1 -1
  17. package/build/types/moneyInput/currencyFormatting.d.ts +2 -2
  18. package/build/types/moneyInput/currencyFormatting.d.ts.map +1 -1
  19. package/build/types/moneyInput/index.d.ts +2 -1
  20. package/build/types/moneyInput/index.d.ts.map +1 -1
  21. package/package.json +1 -1
  22. package/src/common/bottomSheet/__snapshots__/BottomSheet.spec.tsx.snap +1 -1
  23. package/src/common/responsivePanel/ResponsivePanel.tsx +1 -2
  24. package/src/dimmer/Dimmer.tsx +5 -1
  25. package/src/flowNavigation/FlowNavigation.story.js +1 -1
  26. package/src/index.ts +6 -0
  27. package/src/inputs/SelectInput.tsx +2 -2
  28. package/src/inputs/_BottomSheet.tsx +5 -1
  29. package/src/inputs/_Popover.tsx +5 -1
  30. package/src/moneyInput/{MoneyInput.rtl.spec.js → MoneyInput.rtl.spec.tsx} +4 -4
  31. package/src/moneyInput/MoneyInput.spec.js +109 -49
  32. package/src/moneyInput/MoneyInput.story.tsx +6 -14
  33. package/src/moneyInput/{MoneyInput.js → MoneyInput.tsx} +189 -173
  34. package/src/moneyInput/{currencyFormatting.spec.js → currencyFormatting.spec.ts} +2 -2
  35. package/src/moneyInput/{currencyFormatting.js → currencyFormatting.ts} +7 -10
  36. package/src/moneyInput/index.ts +7 -0
  37. package/src/popover/__snapshots__/Popover.spec.js.snap +1 -1
  38. package/src/radioGroup/RadioGroup.js +2 -2
  39. package/src/radioGroup/RadioGroup.rtl.spec.tsx +16 -0
  40. package/src/moneyInput/index.js +0 -1
  41. /package/src/moneyInput/{MoneyInput.messages.js → MoneyInput.messages.ts} +0 -0
package/build/index.js CHANGED
@@ -1557,7 +1557,7 @@ class DimmerManager {
1557
1557
  /**
1558
1558
  * Dimmer refs
1559
1559
  */
1560
-
1560
+ dimmers;
1561
1561
  constructor() {
1562
1562
  this.dimmers = [];
1563
1563
  }
@@ -1711,8 +1711,8 @@ const DimmerWrapper = ({
1711
1711
  theme
1712
1712
  } = componentsTheming.useTheme();
1713
1713
  return open || hasNotExited ? /*#__PURE__*/jsxRuntime.jsx(componentsTheming.ThemeProvider, {
1714
- theme: theme,
1715
- screenMode: screenMode,
1714
+ theme: "personal",
1715
+ screenMode: theme === 'personal' ? screenMode : 'light',
1716
1716
  isNotRootProvider: true,
1717
1717
  children: children
1718
1718
  }) : /*#__PURE__*/jsxRuntime.jsx(jsxRuntime.Fragment, {
@@ -3370,9 +3370,6 @@ const ResponsivePanel = /*#__PURE__*/React.forwardRef(({
3370
3370
  open = false,
3371
3371
  position = exports.Position.BOTTOM
3372
3372
  }, reference) => {
3373
- const {
3374
- className: themeClassname
3375
- } = componentsTheming.useTheme();
3376
3373
  const {
3377
3374
  isMobile
3378
3375
  } = useLayout();
@@ -3391,7 +3388,7 @@ const ResponsivePanel = /*#__PURE__*/React.forwardRef(({
3391
3388
  open: open,
3392
3389
  position: position,
3393
3390
  anchorRef: anchorRef,
3394
- className: classNames__default.default(themeClassname, className),
3391
+ className: className,
3395
3392
  onClose: onClose,
3396
3393
  children: children
3397
3394
  }, "panel");
@@ -5436,6 +5433,7 @@ var DynamicFieldDefinitionList$1 = DynamicFieldDefinitionList;
5436
5433
  const ESCAPED_OPENING_CHEVRON = '<';
5437
5434
  const ESCAPED_CLOSING_CHEVRON = '>';
5438
5435
  class EmphasisHtmlTransformer {
5436
+ tags;
5439
5437
  constructor(whitelistedTags) {
5440
5438
  this.tags = (whitelistedTags || []).map(tag => {
5441
5439
  return {
@@ -6545,8 +6543,8 @@ function BottomSheet({
6545
6543
  getInteractionProps: getReferenceProps
6546
6544
  }), /*#__PURE__*/jsxRuntime.jsx(react.FloatingPortal, {
6547
6545
  children: /*#__PURE__*/jsxRuntime.jsx(componentsTheming.ThemeProvider, {
6548
- theme: theme,
6549
- screenMode: screenMode,
6546
+ theme: "personal",
6547
+ screenMode: theme === 'personal' ? screenMode : 'light',
6550
6548
  isNotRootProvider: true,
6551
6549
  children: /*#__PURE__*/jsxRuntime.jsx(react$1.Transition, {
6552
6550
  show: open,
@@ -6693,8 +6691,8 @@ function Popover({
6693
6691
  getInteractionProps: getReferenceProps
6694
6692
  }), /*#__PURE__*/jsxRuntime.jsx(react.FloatingPortal, {
6695
6693
  children: /*#__PURE__*/jsxRuntime.jsx(componentsTheming.ThemeProvider, {
6696
- theme: theme,
6697
- screenMode: screenMode,
6694
+ theme: "personal",
6695
+ screenMode: theme === 'personal' ? screenMode : 'light',
6698
6696
  isNotRootProvider: true,
6699
6697
  children: /*#__PURE__*/jsxRuntime.jsx(react$1.Transition, {
6700
6698
  show: open,
@@ -7869,20 +7867,17 @@ function getValidLocale(locale) {
7869
7867
  Intl.NumberFormat(noUnderscoreLocale);
7870
7868
  return noUnderscoreLocale;
7871
7869
  } catch {
7872
- return 'en-GB';
7870
+ return DEFAULT_LOCALE;
7873
7871
  }
7874
7872
  }
7875
- function getCurrencyDecimals(currency = '') {
7873
+ function getCurrencyDecimals(currency) {
7876
7874
  const upperCaseCurrency = currency.toUpperCase();
7877
- if (Object.prototype.hasOwnProperty.call(currencyDecimals, upperCaseCurrency)) {
7878
- return currencyDecimals[upperCaseCurrency];
7879
- }
7880
- return DEFAULT_CURRENCY_DECIMALS;
7875
+ return currencyDecimals[upperCaseCurrency] ?? DEFAULT_CURRENCY_DECIMALS;
7881
7876
  }
7882
7877
  function getDecimalSeparator(locale) {
7883
7878
  return isNumberLocaleSupported() ? 1.1.toLocaleString(locale)[1] : '.';
7884
7879
  }
7885
- function parseAmount(number, currency, locale) {
7880
+ function parseAmount(number, currency, locale = DEFAULT_LOCALE) {
7886
7881
  const validLocale = getValidLocale(locale);
7887
7882
  const precision = getCurrencyDecimals(currency);
7888
7883
  const groupSeparator = isNumberLocaleSupported() ? 10000 .toLocaleString(validLocale)[2] : ',';
@@ -7892,53 +7887,67 @@ function parseAmount(number, currency, locale) {
7892
7887
  return Math.abs(parsedAmount);
7893
7888
  }
7894
7889
 
7895
- const Currency = PropTypes__default.default.shape({
7896
- header: PropTypes__default.default.string,
7897
- value: PropTypes__default.default.string,
7898
- label: PropTypes__default.default.string,
7899
- currency: PropTypes__default.default.string,
7900
- note: PropTypes__default.default.string,
7901
- searchable: PropTypes__default.default.string
7902
- });
7903
7890
  const isNumberOrNull = v => neptuneValidation.isNumber(v) || neptuneValidation.isNull(v);
7904
- const formatAmountIfSet = (amount, currency, locale, maxLengthOverride) => {
7891
+ const formatAmountIfSet = ({
7892
+ amount,
7893
+ currency,
7894
+ locale,
7895
+ maxLengthOverride
7896
+ }) => {
7905
7897
  if (maxLengthOverride) {
7906
- return amount || '';
7898
+ return amount != null ? String(amount) : '';
7907
7899
  } else {
7908
7900
  return typeof amount === 'number' ? formatting.formatAmount(amount, currency, locale) : '';
7909
7901
  }
7910
7902
  };
7911
- const parseNumber = (amount, currency, locale, maxLengthOverride) => {
7903
+ const parseNumber = ({
7904
+ amount,
7905
+ currency,
7906
+ locale,
7907
+ maxLengthOverride
7908
+ }) => {
7912
7909
  if (!maxLengthOverride) {
7913
7910
  return parseAmount(amount, currency, locale);
7914
7911
  }
7915
7912
  if (maxLengthOverride && amount.length > maxLengthOverride) {
7916
7913
  return 0;
7917
7914
  }
7918
- return +amount;
7915
+ return Number(amount);
7919
7916
  };
7920
7917
  const inputKeyCodeAllowlist = new Set([KeyCodes.BACKSPACE, KeyCodes.DELETE, KeyCodes.COMMA, KeyCodes.PERIOD, KeyCodes.DOWN, KeyCodes.UP, KeyCodes.LEFT, KeyCodes.RIGHT, KeyCodes.ENTER, KeyCodes.ESCAPE, KeyCodes.TAB]);
7921
7918
  const inputKeyAllowlist = new Set([Key.PERIOD, Key.COMMA]);
7922
7919
  class MoneyInput extends React.Component {
7920
+ static defaultProps = {
7921
+ size: exports.Size.LARGE,
7922
+ classNames: {},
7923
+ selectProps: {}
7924
+ };
7925
+ amountFocused = false;
7923
7926
  constructor(props) {
7924
7927
  super(props);
7925
- const {
7926
- locale
7927
- } = this.props.intl;
7928
- this.formatMessage = this.props.intl.formatMessage;
7929
7928
  this.state = {
7930
7929
  searchQuery: '',
7931
- formattedAmount: formatAmountIfSet(props.amount, props.selectedCurrency.currency, locale, props.maxLengthOverride),
7932
- locale
7930
+ formattedAmount: formatAmountIfSet({
7931
+ amount: props.amount,
7932
+ currency: props.selectedCurrency.currency,
7933
+ locale: props.intl.locale,
7934
+ maxLengthOverride: props.maxLengthOverride
7935
+ }),
7936
+ locale: props.intl.locale
7933
7937
  };
7934
7938
  }
7935
7939
  UNSAFE_componentWillReceiveProps(nextProps) {
7936
7940
  this.setState({
7937
- locale: nextProps?.intl?.locale
7941
+ locale: nextProps.intl.locale
7938
7942
  });
7939
7943
  if (!this.amountFocused) {
7940
7944
  this.setState({
7941
- formattedAmount: formatAmountIfSet(nextProps.amount, nextProps.selectedCurrency.currency, nextProps?.intl?.locale, nextProps.maxLengthOverride)
7945
+ formattedAmount: formatAmountIfSet({
7946
+ amount: nextProps.amount,
7947
+ currency: nextProps.selectedCurrency.currency,
7948
+ locale: nextProps.intl.locale,
7949
+ maxLengthOverride: nextProps.maxLengthOverride
7950
+ })
7942
7951
  });
7943
7952
  }
7944
7953
  }
@@ -7958,16 +7967,26 @@ class MoneyInput extends React.Component {
7958
7967
  }
7959
7968
  };
7960
7969
  handlePaste = event => {
7961
- const paste = (event.clipboardData || window.clipboardData).getData('text');
7970
+ const paste = event.clipboardData.getData('text');
7962
7971
  const {
7963
7972
  locale
7964
7973
  } = this.state;
7965
- const parsed = neptuneValidation.isEmpty(paste) ? null : parseNumber(paste, this.props.selectedCurrency.currency, locale, this.props.maxLengthOverride);
7974
+ const parsed = neptuneValidation.isEmpty(paste) ? null : parseNumber({
7975
+ amount: paste,
7976
+ currency: this.props.selectedCurrency.currency,
7977
+ locale: locale,
7978
+ maxLengthOverride: this.props.maxLengthOverride
7979
+ });
7966
7980
  if (isNumberOrNull(parsed)) {
7967
7981
  this.setState({
7968
- formattedAmount: formatAmountIfSet(parsed, this.props.selectedCurrency.currency, locale, this.props.maxLengthOverride)
7982
+ formattedAmount: formatAmountIfSet({
7983
+ amount: parsed,
7984
+ currency: this.props.selectedCurrency.currency,
7985
+ locale: locale,
7986
+ maxLengthOverride: this.props.maxLengthOverride
7987
+ })
7969
7988
  });
7970
- this.props.onAmountChange(parsed);
7989
+ this.props.onAmountChange?.(parsed);
7971
7990
  }
7972
7991
  event.preventDefault();
7973
7992
  };
@@ -7978,9 +7997,14 @@ class MoneyInput extends React.Component {
7978
7997
  this.setState({
7979
7998
  formattedAmount: value
7980
7999
  });
7981
- const parsed = neptuneValidation.isEmpty(value) ? null : parseNumber(value, this.props.selectedCurrency.currency, this.state.locale, this.props.maxLengthOverride);
8000
+ const parsed = neptuneValidation.isEmpty(value) ? null : parseNumber({
8001
+ amount: value,
8002
+ currency: this.props.selectedCurrency.currency,
8003
+ locale: this.state.locale,
8004
+ maxLengthOverride: this.props.maxLengthOverride
8005
+ });
7982
8006
  if (isNumberOrNull(parsed)) {
7983
- this.props.onAmountChange(parsed);
8007
+ this.props.onAmountChange?.(parsed);
7984
8008
  }
7985
8009
  };
7986
8010
  onAmountBlur = () => {
@@ -7990,68 +8014,67 @@ class MoneyInput extends React.Component {
7990
8014
  onAmountFocus = () => {
7991
8015
  this.amountFocused = true;
7992
8016
  };
7993
- mapOption = item => {
7994
- return {
7995
- type: 'option',
7996
- value: item,
7997
- filterMatchers: [item.value, item.label, item.note, item.searchable]
7998
- };
7999
- };
8000
8017
  getSelectOptions() {
8001
- const selectOptions = [...filterOptionsForQuery(this.props.currencies, this.state.searchQuery)];
8002
- let formattedOptions = [];
8003
- let groupIndex = null;
8018
+ const selectOptions = filterCurrenciesForQuery(this.props.currencies, this.state.searchQuery);
8019
+ const formattedOptions = [];
8020
+ let currentGroupOptions;
8004
8021
  selectOptions.forEach(item => {
8005
- if (item.header) {
8022
+ if (item.header != null) {
8023
+ currentGroupOptions = [];
8006
8024
  formattedOptions.push({
8007
8025
  type: 'group',
8008
8026
  label: item.header,
8009
- options: []
8027
+ options: currentGroupOptions
8010
8028
  });
8011
- groupIndex = formattedOptions.length - 1;
8012
8029
  } else {
8013
- if (groupIndex === null) {
8014
- formattedOptions.push(this.mapOption(item));
8015
- } else {
8016
- formattedOptions[groupIndex]?.options.push(this.mapOption(item));
8017
- }
8030
+ (currentGroupOptions ?? formattedOptions).push({
8031
+ type: 'option',
8032
+ value: item,
8033
+ filterMatchers: [item.value, item.label, item.note ?? '', item.searchable ?? '']
8034
+ });
8018
8035
  }
8019
8036
  });
8020
8037
  return formattedOptions;
8021
8038
  }
8022
8039
  setAmount() {
8023
8040
  this.setState(previousState => {
8024
- const parsed = parseNumber(previousState.formattedAmount, this.props.selectedCurrency.currency, previousState.locale, this.props.maxLengthOverride);
8041
+ const parsed = parseNumber({
8042
+ amount: previousState.formattedAmount,
8043
+ currency: this.props.selectedCurrency.currency,
8044
+ locale: previousState.locale,
8045
+ maxLengthOverride: this.props.maxLengthOverride
8046
+ });
8025
8047
  if (!isNumberOrNull(parsed)) {
8026
8048
  return {
8027
8049
  formattedAmount: previousState.formattedAmount
8028
8050
  };
8029
8051
  }
8030
8052
  return {
8031
- formattedAmount: formatAmountIfSet(parsed, this.props.selectedCurrency.currency, previousState.locale, this.props.maxLengthOverride)
8053
+ formattedAmount: formatAmountIfSet({
8054
+ amount: parsed,
8055
+ currency: this.props.selectedCurrency.currency,
8056
+ locale: previousState.locale,
8057
+ maxLengthOverride: this.props.maxLengthOverride
8058
+ })
8032
8059
  };
8033
8060
  });
8034
8061
  }
8035
8062
  handleSelectChange = value => {
8036
8063
  this.handleSearchChange('');
8037
- this.props.onCurrencyChange(value);
8064
+ this.props.onCurrencyChange?.(value);
8038
8065
  };
8039
8066
  handleCustomAction = () => {
8040
8067
  this.handleSearchChange('');
8041
- if (this.props.onCustomAction) {
8042
- this.props.onCustomAction();
8043
- }
8068
+ this.props.onCustomAction?.();
8044
8069
  };
8045
8070
  handleSearchChange = searchQuery => {
8046
8071
  this.setState({
8047
8072
  searchQuery
8048
8073
  });
8049
- if (this.props.onSearchChange) {
8050
- this.props.onSearchChange({
8051
- searchQuery,
8052
- filteredOptions: filterOptionsForQuery(this.props.currencies, searchQuery)
8053
- });
8054
- }
8074
+ this.props.onSearchChange?.({
8075
+ searchQuery,
8076
+ filteredOptions: filterCurrenciesForQuery(this.props.currencies, searchQuery)
8077
+ });
8055
8078
  };
8056
8079
  style = className => this.props.classNames[className] || className;
8057
8080
  render() {
@@ -8091,7 +8114,12 @@ class MoneyInput extends React.Component {
8091
8114
  inputMode: "decimal",
8092
8115
  disabled: disabled,
8093
8116
  maxLength: maxLengthOverride,
8094
- placeholder: formatAmountIfSet(this.props.placeholder, this.props.selectedCurrency.currency, this.state.locale, this.props.maxLengthOverride),
8117
+ placeholder: formatAmountIfSet({
8118
+ amount: this.props.placeholder,
8119
+ currency: this.props.selectedCurrency.currency,
8120
+ locale: this.state.locale,
8121
+ maxLengthOverride: this.props.maxLengthOverride
8122
+ }),
8095
8123
  autoComplete: "off",
8096
8124
  onKeyDown: this.handleKeyDown,
8097
8125
  onChange: this.onAmountChange,
@@ -8136,11 +8164,11 @@ class MoneyInput extends React.Component {
8136
8164
  // eslint-disable-next-line jsx-a11y/click-events-have-key-events
8137
8165
  jsxRuntime.jsx("div", {
8138
8166
  role: "button",
8139
- tabIndex: "0",
8167
+ tabIndex: 0,
8140
8168
  onClick: this.handleCustomAction,
8141
8169
  children: this.props.customActionLabel
8142
- }) : null,
8143
- placeholder: this.formatMessage(messages$3.selectPlaceholder),
8170
+ }) : undefined,
8171
+ placeholder: this.props.intl.formatMessage(messages$3.selectPlaceholder),
8144
8172
  filterable: true,
8145
8173
  filterPlaceholder: this.props.searchPlaceholder,
8146
8174
  disabled: disabled,
@@ -8157,25 +8185,25 @@ class MoneyInput extends React.Component {
8157
8185
  });
8158
8186
  }
8159
8187
  }
8160
- function filterOptionsForQuery(options, query) {
8188
+ function filterCurrenciesForQuery(currencies, query) {
8161
8189
  if (!query) {
8162
- return options;
8190
+ return [...currencies];
8163
8191
  }
8164
- const filteredOptions = removeDuplicateValueOptions(options).filter(option => isCurrencyOptionAndFitsQuery(option, query));
8192
+ const options = currencies.filter(option => option.header == null);
8193
+ const filteredOptions = removeDuplicateValueOptions(options).filter(option => currencyOptionFitsQuery(option, query));
8165
8194
  return sortOptionsLabelsToFirst(filteredOptions, query);
8166
8195
  }
8167
8196
  function removeDuplicateValueOptions(options) {
8168
- const result = [];
8169
- const resultValues = [];
8170
- options.forEach(option => {
8171
- if (option.value && !resultValues.includes(option.value)) {
8172
- result.push(option);
8173
- resultValues.push(option.value);
8197
+ const uniqueValues = new Set();
8198
+ return options.filter(option => {
8199
+ if (!uniqueValues.has(option.value)) {
8200
+ uniqueValues.add(option.value);
8201
+ return true;
8174
8202
  }
8203
+ return false;
8175
8204
  });
8176
- return result;
8177
8205
  }
8178
- function isCurrencyOptionAndFitsQuery(option, query) {
8206
+ function currencyOptionFitsQuery(option, query) {
8179
8207
  if (!option.value) {
8180
8208
  return false;
8181
8209
  }
@@ -8200,43 +8228,6 @@ function sortOptionsLabelsToFirst(options, query) {
8200
8228
  return 0;
8201
8229
  });
8202
8230
  }
8203
- MoneyInput.propTypes = {
8204
- id: PropTypes__default.default.string,
8205
- currencies: PropTypes__default.default.arrayOf(Currency).isRequired,
8206
- selectedCurrency: Currency.isRequired,
8207
- onCurrencyChange: PropTypes__default.default.func,
8208
- placeholder: PropTypes__default.default.number,
8209
- amount: PropTypes__default.default.number,
8210
- size: PropTypes__default.default.oneOf(['sm', 'md', 'lg']),
8211
- onAmountChange: PropTypes__default.default.func,
8212
- addon: PropTypes__default.default.node,
8213
- searchPlaceholder: PropTypes__default.default.string,
8214
- /**
8215
- * Allows the consumer to react to searching, while the search itself is handled internally. Called with `{ searchQuery: string, filteredOptions: Currency[] }`
8216
- */
8217
- onSearchChange: PropTypes__default.default.func,
8218
- customActionLabel: PropTypes__default.default.node,
8219
- onCustomAction: PropTypes__default.default.func,
8220
- classNames: PropTypes__default.default.objectOf(PropTypes__default.default.string),
8221
- selectProps: PropTypes__default.default.object,
8222
- maxLengthOverride: PropTypes__default.default.number
8223
- };
8224
- MoneyInput.defaultProps = {
8225
- id: null,
8226
- size: exports.Size.LARGE,
8227
- addon: null,
8228
- searchPlaceholder: '',
8229
- onSearchChange: undefined,
8230
- onCurrencyChange: null,
8231
- placeholder: null,
8232
- amount: null,
8233
- onAmountChange: null,
8234
- customActionLabel: '',
8235
- onCustomAction: null,
8236
- classNames: {},
8237
- selectProps: {},
8238
- maxLengthOverride: null
8239
- };
8240
8231
  var MoneyInput$1 = reactIntl.injectIntl(MoneyInput);
8241
8232
 
8242
8233
  const NavigationOptionList = ({
@@ -10509,7 +10500,8 @@ class RadioGroup extends React.Component {
10509
10500
  const {
10510
10501
  selectedValue
10511
10502
  } = this.state;
10512
- return radios && radios.length > 0 ? /*#__PURE__*/jsxRuntime.jsx(jsxRuntime.Fragment, {
10503
+ return radios && radios.length > 0 ? /*#__PURE__*/jsxRuntime.jsx("div", {
10504
+ role: "radiogroup",
10513
10505
  children: radios.map(({
10514
10506
  id,
10515
10507
  avatar,