Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: reactive chain and token properties from config #294

Merged
merged 32 commits into from
Sep 18, 2024

Conversation

DNR500
Copy link
Contributor

@DNR500 DNR500 commented Sep 4, 2024

Jira: LF-9902

How to set up testing in the playground

Some tooling has been developed to test this functionality in the playground.

To access it

  • Open the Playground
  • Go to the “Playground settings”
  • Click the Dev view button
  • A control for “Form values” will appear in the Design tools
  • You can use this to dynamically change the values

There are two ways you can update the form values in the Widget

  • using config - this uses reactive values in the config and requires some management of those values for updates
  • using the formRef - this provides an function that you can use to update values in the widgets form

Note: Config overrides URL params
Important point from this PR - Config values override URL parameters.

So you need to ensure that on first page load non of the form values that can be set in the URL are featured in the config that the Widget initialises.

So fromAmount, fromChain, fromToken, toAddress, toChain, toToken and toAmount should not be set to allow the URL to perform the initial set up.

On first page load if you have both values in the config and the url then the url search params will be rewritten to match the config values

Updating form values via the config

Once widget has initialised and has full rendered you can update the form values in the Widget by updating the config.

To perform an update you should only include the form values in the config that you want to change and ensure this is passed to the Widget.

So if you want to change the fromChain and fromToken and nothing else you should include only include those values

You also need to set the formUpdateKey. This should be a unique randomly generated key. Using this key ensures that the form values are updated in the widget - essentially forcing an update in the Widget even if the config is otherwise unchanged. This can avoid some edge case issue that might arise when setting values in the Widget via a mix of config and user actions via the Widgets UI.

So your new config might look like this

{
    fromChain: 10,
    fromToken: ‘0x94b008aA00579c1307B0EF2c499aD98a8ce58e58’,
    // use the date object to generate a unique value
    formUpdateKey: new Date().valueOf().toString()

    // might feature other config values but should not include other form values…
}

You can also reset the form values and their fields to an empty state using undefined

This example resets only the fromChain and fromToken fields

{
    fromChain: undefined,
    fromToken: undefined,
    // use the date object to generate a unique value
    formUpdateKey: new Date().valueOf().toString()

    // might feature other config values but should not include other form values…
}

Note that undefined as a value is used to make the Widget reset to an empty form field for that property. The absence property rom the config object means they will remain unchanged.

Updating form values via the form ref

This method provides developers using the Widget a way to set the form values directly in Widget using a function call. This approach is more imperative and might be better suited to some situations. By passing a ref object to the widget you can access a function to set values directly in the form.

For example

import type { FormState } from '@lifi/widget';
import { LiFiWidget } from '@lifi/widget';

const formRef = useRef<FormState>(null);

<LiFiWidget
  config={config}
  integrator="li.fi-playground"
  formRef={formRef}
/>

Once initialised you can use the ref as follows

formRef.current?.setFieldValue( ‘fromChain’, 10, { setUrlSearchParam: true });

I think this currently update the url and the widget fields as expected.

To set fromChain and fromToken

formRef.current?.setFieldValue( 
    'fromChain',
    10, 
    { setUrlSearchParam: true }
);
formRef.current?.setFieldValue(
    'fromToken', 
    '0x94b008aA00579c1307B0EF2c499aD98a8ce58e58', 
    { setUrlSearchParam: true }
);

To reset fromChain and fromToken

formRef.current?.setFieldValue( 
    'fromChain',
    undefined, 
    { setUrlSearchParam: true }
);
formRef.current?.setFieldValue(
    'fromToken', 
    undefined 
    { setUrlSearchParam: true }
);

To set fromAmount

formRef.current?.setFieldValue( 
   'fromAmount',
    '10', 
    { setUrlSearchParam: true }
);

to reset fromAmount

formRef.current?.setFieldValue(
    'fromAmount', 
    undefined 
    { setUrlSearchParam: true }
);

To set toAddress

formRef.current?.setFieldValue( 
    ‘toAddress’,
    {
      address: '0x4577a46A3eCf44E0ed44410B7793977ffbe22CE0',
      chainType: ChainType.EVM,
    }, 
    { setUrlSearchParam: true }
);

You can also include a name to display

formRef.current?.setFieldValue( 
    'toAddress',
    {
      name: 'Lenny',
      address: '0x552008c0f6870c2f77e5cC1d2eb9bdff03e30Ea9',
      chainType: ChainType.EVM,
    }, 
    { setUrlSearchParam: true }
);

Or you can just set the address as a string

formRef.current?.setFieldValue( 
    'toAddress',
    '0x552008c0f6870c2f77e5cC1d2eb9bdff03e30Ea9'
    { setUrlSearchParam: true }
);

to reset toAddress

formRef.current?.setFieldValue(
    'toAddress', 
    undefined 
    { setUrlSearchParam: true }
);

@DNR500 DNR500 added WIP Work in progress testing labels Sep 4, 2024
Copy link

github-actions bot commented Sep 4, 2024

Hey! This is your new endopint: https://876515f8.widget-spikesetti.pages.dev

Copy link

github-actions bot commented Sep 6, 2024

Hey! This is your new endopint: https://fdbec9c7.widget-spikesetti.pages.dev

Copy link

github-actions bot commented Sep 6, 2024

Hey! This is your new endopint: https://6d73ec0b.widget-spikesetti.pages.dev

Copy link

github-actions bot commented Sep 6, 2024

Hey! This is your new endopint: https://bd3a4f61.widget-spikesetti.pages.dev

Copy link

Hey! This is your new endopint: https://fbae9b7a.widget-spikesetti.pages.dev

Copy link

Hey! This is your new endopint: https://6459e081.widget-spikesetti.pages.dev

Copy link

Hey! This is your new endopint: https://6c0faad9.widget-spikesetti.pages.dev

Copy link

Hey! This is your new endopint: https://a93c34d0.widget-spikesetti.pages.dev

Comment on lines +34 to +36
export const FormStoreProvider: React.FC<FormStoreProviderProps> = ({
children,
formRef,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we should wrap this in forwardRef instead of passing formRef as a prop?

Copy link
Contributor Author

@DNR500 DNR500 Sep 16, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that only applies if you want to use 'ref' as the prop name - I think keeping this as formRef is actually a good thing here. I always think that ref is generally used to refer to DOM elements as it mosts common use. Also come React 19 we are going to have to stop using forwardRef anyways

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, in React 19 we will have ref prop without the need to wrap the component in forwardRef, however to use ref prop now it is still required 😄 Agree, ref is often used for DOM elements and making a component controlled with ref is also a common use-case and we use useImperativeHandle for that.

Comment on lines 264 to 268
export type FormFunctions =
| {
setFieldValue: SetFieldValueFunc;
}
| undefined;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why this can be undefined?

Copy link
Contributor Author

@DNR500 DNR500 Sep 16, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because the initial state of the useRef will be undefined before the functions are added to it. That type is essentially use like this

const formRef = useRef<FormFunctions>()

formRef is passed to the LiFiWidget, without undefined stated in the type you get a type error when first passing the formRef it to the Widget as is value is initially undefined.

<LiFiWidget
          ...
          formRef={formRef}
          ...
/>

Copy link
Contributor Author

@DNR500 DNR500 Sep 17, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll change this to

export type FormState = {
  setFieldValue: SetFieldValueFunction;
};

And point of use should change to

const formRef = useRef<FormState>(null)

That seems cleaner

Copy link

Hey! This is your new endopint: https://a5c818a6.widget-spikesetti.pages.dev

Copy link

Hey! This is your new endopint: https://4786a963.widget-spikesetti.pages.dev

Copy link

Hey! This is your new endopint: https://aa6c81fe.widget-spikesetti.pages.dev

Copy link

Hey! This is your new endopint: https://cc30e70f.widget-spikesetti.pages.dev

Copy link

Hey! This is your new endopint: https://bc13535d.widget-spikesetti.pages.dev

@chybisov chybisov merged commit 1ff7cfc into main Sep 18, 2024
1 check passed
@chybisov chybisov deleted the spike-setting-chain-and-token-via-config branch September 18, 2024 08:33
Copy link

Hey! This is your new endopint: https://e9b692b3.widget-spikesetti.pages.dev

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants