Using React Currency Selector

Am trying to provide a better UI to enable users enter budget amounts in millions, billions or trillions in custom dexterity content types.

Wonder how we could enable using custom react-currency-input-field or something similar for default schema.Decimal fields?

The "trick" is to understand Volto's widget lookup mechanism and how it uses config.widgets to configure the available widgets. See also the widgets registry. At the most simple, you can register a custom input widget, like

config.widgets.id.budget_amount = ReactCurrencyWidget

where ReactCurrencyWidget is your own custom widget that mimics the Volto widgets and properly adapts input/callback to react-currency-input-field format.

1 Like

@tiberiuichim Sweet!

Thank you once again for pointing me into the direction.

1 Like

@tiberiuichim I had totally missed reading about widgets in volto docs. So I have added a link to surface this tip directly from configuration page.

Adding the following config to my custom view doesn't seem to work. I am not sure how to check if this setting is overriding the decimal and integer fields in the forms.

import CurrencyInput from 'react-currency-input-field';

const applyConfig = (config) => {
  config.widgets.id.budget_amount = CurrencyInput;
  return config;
};

It should work for a field with the id of budget_amount. Use a custom component, just to confirm that your widget is used.

const applyConfig = (config) => {
  config.widgets.id.budget_amount = (props) => {
      console.log('it works');
      return null;
  };
  return config;
};

If that doesn't work, then you have a problem with the configuration loading, maybe? Is applyConfig executed?

@tiberiuichim The applyConfig is never called even from a custom component. Need to figure out what went wrong in my config.js settings.


import {
  PersonView,
  ContactView,
  OrganizationView,
  SourceView,
  OtherName,
  RelationshipView,
  IdentifierView,
  MembershipView,
  PostView,
  OwnershipView,
  ExtraciveConcessionView,
  InfrastructureProjectView,
  OCDSDocumentView,
  ContractingProcessView,
  ModificationView,
  OCDSReleaseView,
  TenderView,
  AwardView,
  OCDSItemView,
  AreaView,
  IssueView,
  IssueSourceView,
  CustomSearchViewBlock,
  CustomSearchEditBlock,
} from './components';

// All your imports required for the config here BEFORE this line
import '@plone/volto/config';

export default function applyConfig(config) {
  // Add here your project's configuration here by modifying `config` accordingly

  (config.blocks.blocksConfig.customsearch = {
    id: 'customsearch',
    title: 'Custom Search',
    icon: 'world',
    group: 'common',
    view: CustomSearchViewBlock,
    edit: CustomSearchEditBlock,
    restricted: false,
    mostUsed: true,
    security: {
      addPermission: [],
      view: [],
    },
  }),
    (config.views = {
      ...config.views,
      contentTypesViews: {
        ...config.views.contentTypesViews,
        Person: PersonView,
        'Contact Detail': ContactView,
        Organization: OrganizationView,
        Source: SourceView,
        'Other Name': OtherName,
        Relationship: RelationshipView,
        Identifier: IdentifierView,
        Membership: MembershipView,
        Post: PostView,
        'Ownership Control Statement': OwnershipView,
        'Extractive Concession': ExtraciveConcessionView,
        'Infrastructure Project': InfrastructureProjectView,
        'OCDS Document': OCDSDocumentView,
        'Contracting Process': ContractingProcessView,
        'OCDS Release': OCDSReleaseView,
        Tender: TenderView,
        Award: AwardView,
        'OCDS Item': OCDSItemView,
        Area: AreaView,
        Issue: IssueView,
        'Issue Source': IssueSourceView,
        Modification: ModificationView,
      },
    });

  return config;
}

[eslint] Expected an assignment or function call and instead saw an expression. [E]

Remove the first parens and fix code accordingly.

(config.blocks.blocksConfig.customsearch becomes config.blocks.blocksConfig.customsearch = ...

Ah! Good catch @tiberiuichim Looks the prettier VSCode plugin was adding these parens. I'll need to add config.js to prettier ignore list.

I have added a custom component in src/components/Widgets and added the following lines to config.js.

  config.widgets.id = {
    ...config.widgets.id, 
    budget_amount: CurrencyWidget,
    award_amount : CurrencyWidget,

  }, 

Now target fields use my custom input component instead of default NumberInput.

Thanks for all your help @tiberiuichim Kudos!

Prettier integration is ok, don't disable it. I think what happened is that you had some ambiguous code at some point and prettier reformatted as it saw fit. But you need to "catch" these situations and go back and fix the code so that it formats correctly.

1 Like