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

Remove auto-save logic from EditFreeCampaign's shipping rate and tax configuration #326

Merged
merged 9 commits into from
Mar 12, 2021

Conversation

tomalec
Copy link
Member

@tomalec tomalec commented Mar 11, 2021

Changes proposed in this Pull Request:

  • Create SetupFreeListings w/o auto-save, and use it in EditFreeCampaign
    It's a modified twin of the one used in onboarding setup, but it has removed saving logic and PreLaunchChecklist.
    The auto-save functionality was removed only from the "master form", but not from all its descendant components yet. 48f4b3a

  • Make SetupFreeListings's step header configurable. Previously it was hard-coded, we will need that step&form to be used on different steps. 3ab3311

  • Duplicate ShippingRate and ShippingTime for EditCampaign, to remove autosaving from the leaf components, and tur them to be re-usable ones. Components are duplicated to avoid regression issues with existing onboarding flow, due to lack of tests. c0461ba

  • Remove auto-save logic from the shared ShippingRateSetup. The state is now stored locally in ShippingCountriesForm, and events are propagated there so we could attach a saving strategy at this point.

  • Update save button labels for shipping rate add/edit modals, as described at Add edit free campaign page flow #156 (comment). fa2273d

Implements a part of #156

Screenshots:

Detailed test instructions:

  1. git co feature/156-edit-product-listings && npm install && npm run build
  2. Got to Marketing > Google (Dashboard) > Edit > Continue
  3. Check step header
  4. Check the sections inside the form if they matches (pre-"combined shipping rates & times") version of Figma designs: https://www.figma.com/file/jZUpa8eTrnrK1Lwt2ry7zk/Native-Google-Integration?node-id=4164%3A607
  5. Open browser devtools and check that no request is being made when changing anything I Shipping rate and Tax rate

Still not covered here:

...and to be addressed in separate PRs to divide work, limit conflicts, cut off the work before starting redesigning "combined shipping rates and times", cut off the work before my AFK.

  • redesign UI for combined shipping rates and times.
  • remove autosave from shipping time section
  • save the entire form at the final "save" button.

Additional notes:

  1. Currently, the CS check on Travis fails, as this PR assumes Change eslint jsdoc syntax to typescript, #334 will be merged before. I removed eslint-disable jsdoc/valid-typess that were here, to make sure there will be no leftovers once both PRs are merged.

tomalec added 4 commits March 10, 2021 14:44
It's a modified copy of  `/js/src/setup-mc/setup-stepper/setup-free-listings/index.js` and `/js/src/setup-mc/setup-stepper/setup-free-listings/form-content.js`. It has removed saving logic and `PreLaunchChecklist`.
Some code doc references are added to both sides.
The auto-save functionality was not complately removed, as it is still coded in leaf components. That will be removed later.

(cherry picked and modified from commit 0fc7670)

(cherry picked from commit 7d5a9a6)
Make it a prop for `.~/components/.../hero` and `.~/edit-free-campaign/setup-free-listings`. Hard-code it in `.~/setup-mc/setup-stepper/setup-free-listings`, to limit the number of changes there.
to remove autosaving from the leaf components, and tur them to be re-usable ones. Components are duplicated to avoid regression issues with existing onboarding flow, due to lack of tests.

Cross-reference duplicates.
Comment on lines 37 to 44
onChange(
{
countries: newValue.countries,
currency: newValue.currency,
price: newValue.price,
},
deletedCountries
);
Copy link
Member

Choose a reason for hiding this comment

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

This could have been like the following?

onChange(newValue, deletedCountries)

Comment on lines +23 to +26
const {
loading: loadingShippingRates,
data: shippingRates,
} = useShippingRates();
Copy link
Member

Choose a reason for hiding this comment

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

As per our note in #288, I'm thinking we should not use useShippingRates in here, but instead use useShippingRates in the main big form level at js/src/edit-free-campaign/setup-free-listings/index.js, like this:

// This is the component having the main big form containing all fields in the page. 
const SetupFreeListings = ( { stepHeader } ) => {
	const { settings } = useSettings();
	const { data: shippingRates } = useShippingRates();  // load shipping rates here, so that we can put it as initial value in the form below, just like settings.

	// This will be called in manual save upon clicking save button. You will have access to the form values and the original values from the hooks above, which will allow you to compare the values and programmatically call shipping rates delete API. 
	const handleSubmitCallback = () => {};

	// ...

return ( 
    <Form
        initialValues={ {
            shipping_rate: settings.shipping_rate,
            shipping_rate-rows: shippingRates,   // set shipping rates as form initial values. This should then be the source of truth for the main big form, which can then be accessible for manual save and auto save. This should be an array of non-aggregated `{ countryCode, price, currency }`.
            offers_free_shipping: settings.offers_free_shipping,
            free_shipping_threshold: settings.free_shipping_threshold,
            ...
        } }
        validate={ handleValidate }
        onSubmitCallback={ handleSubmitCallback }
    >
    { ( formProps ) => {
        // auto-save (including shipping rates shall be implemented inside FormContent.
        return <FormContent formProps={ formProps } />;
    } }
    </Form>
)

With the above, you can then get the shipping rates from the formProps (source of truth).

Copy link
Member Author

Choose a reason for hiding this comment

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

I would consider it in future PRs. However, given the redesign #255, I start to think maybe it's better to put it deeper than the main form. We could put it inside "<SimpleShippingRate&TimeForm>" which may or may not be loaded, or lazy load, to avoid holding the main form load, if it may not be needed at all if a user has "more complex setup" an will do that manually in Google MC

Comment on lines +44 to +79
// TODO: move those handlers up to the ancestors and consider optimizing upserting.
function handleDelete( deletedCountries ) {
updateShippingRates(
shippingRates.filter(
( rate ) => ! deletedCountries.includes( rate.countryCode )
)
);
}
function handleAdd( { countries, currency, rate } ) {
// Split aggregated rate, to individial rates per country.
const addedIndividualRates = countries.map( ( countryCode ) => ( {
countryCode,
currency,
rate, // TODO: unify that
} ) );

updateShippingRates( shippingRates.concat( addedIndividualRates ) );
}
function handleChange(
{ countries, currency, price },
deletedCountries = []
) {
deletedCountries.forEach( ( countryCode ) =>
actualCountries.delete( countryCode )
);

// Upsert rates.
countries.forEach( ( countryCode ) => {
actualCountries.set( countryCode, {
countryCode,
currency,
rate: price, // TODO: unify that
} );
} );
updateShippingRates( Array.from( actualCountries.values() ) );
}
Copy link
Member

Choose a reason for hiding this comment

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

About your TODO comment, I'm thinking we might still need the handlers. We need to call the updateShippingRate to update this local form state, and then have a debounced callback to propagate the changes up to the main big form state. This is actually similar to CountriesPriceInputForm.

A lil bit more context on CountriesPriceInputForm: it is called a "form" because it uses local state to store user's input, however it does not use the <Form> component because we can't have nested forms.

With the debounced callback implemented, what we will see is users will be able to immediately see their changes in the input (due to the local form state), and if the price is the same as another aggregated group, after the debounce delay with the upward propagation to update the big form state, the big form will re-render and it will be merged with the aggregated group.

Copy link
Member Author

Choose a reason for hiding this comment

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

Thanks, I forgot that debounce was not only to limit the flood of HTTP requests but also to limit disturbance in UI.
I restored debouncing, but keep that in CountriesPriceInput, I hope that's fine for you.

I'm not sure if/why we would have to debounce the change also from the entire form up. I think:

  1. In edit flow/save-on-click the big form would just record the changes passively, to submit the end result once requested by the user click.
  2. In onboarding/autosave flow the debouncing is done close to the input field, and then ShippingCountriesForm.Props.onChange is limited to: clicking AddRateModals "save", EditRateModal's "save", already delayed "input", so I think we can safely forward those events as they come.

Copy link
Member

Choose a reason for hiding this comment

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

In edit flow/save-on-click the big form would just record the changes passively, to submit the end result once requested by the user click.

If you don't propagate the changes up to the big form, then we won't have the shipping rates data in the save-on-click form submit event handler, isn't it?

PS: the React Form component that we use there isn't like HTML form 😅 (I think that's what you are thinking).

Comment on lines 49 to 55
<CountriesPriceInputForm
initialValue={ {
countries: selectedCountryCodes,
price: '',
currency: currencyCode,
} }
/>
Copy link
Member

Choose a reason for hiding this comment

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

I actually thought you could have reused CountriesPriceInputForm but just remove the upsertShippingRate inside it. Thinking deeper into it, I think you might be doing the right thing here by not using it.

tomalec added 4 commits March 11, 2021 18:06
as suggested at #326 (comment).

Update the related code docs.
To avoid distracting users while typing with countries being re-grouped.
Addresses #326 (comment).
as it will not be needed once #334 will be (hopefully) merged.
@tomalec tomalec changed the title [WIP] Remove auto-save logic from EditFreeCampaign's shipping configuration Remove auto-save logic from EditFreeCampaign's shipping rate and tax configuration Mar 12, 2021
@tomalec tomalec requested a review from a team March 12, 2021 00:05
Copy link
Member

@eason9487 eason9487 left a comment

Choose a reason for hiding this comment

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

LGTM. Left a question that may no need to block this PR.


There is a use case that will cause a temporary inconsistent UI behavior and internal data sync, not sure if it's within the scope of this PR. Please ignore this if it will be changed in future development or not a concern. Here are the steps:

  1. Change any country's shipping rate
  2. Change the free shipping threshold
  3. Switch to "I have a more complex shipping setup ..."
  4. Switch back to "I have a fairly simple shipping setup ..."

Then the country's shipping rate will be rollbacked, but the free shipping threshold is kept.

Kapture 2021-03-12 at 18 30 08

return (
<div className="gla-setup-free-listings">
<Hero stepHeader={ stepHeader } />
{ /* TODO: 'shippingTimeOption-rows' should be removed, and use shipping time API instead. */ }
Copy link
Member

Choose a reason for hiding this comment

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

Reference: 08bf8b1 (Just for referencing the related change as a note)

@tomalec
Copy link
Member Author

tomalec commented Mar 12, 2021

There is a use case that will cause a temporary inconsistent UI behavior and internal data sync, not sure if it's within the scope of this PR. Please ignore this if it will be changed in future development or not a concern. Here are the steps:

Thanks for finding that!
This seems to be an issue with our debounced save. If you manage to switch before debounced delay passes, it's not saved.
The issue also applies to the onboarding setup flow. It is just easier to hit it here, as I extended the delay from 500 to 1000ms.

I created a separate issue for that #338

@tomalec tomalec merged commit 5e026f8 into trunk Mar 12, 2021
@tomalec tomalec deleted the feature/156-edit-product-listings branch March 12, 2021 13:23
@ecgan
Copy link
Member

ecgan commented Mar 12, 2021

@tomalec , I think that issue mentioned by @eason9487 happens because right now the shipping rates are stored in local state in .../configure-product-listings/shipping-rate/shipping-rate-setup/countries-form.js. When we click on the "more complex shipping rate setup", the countries-form component is unmounted and the state would then be gone.

To solve this, if we propagate the changes up to the main big form (as I commented here in #326 (comment)), then it shouldn't have any problem.

@tomalec
Copy link
Member Author

tomalec commented Mar 12, 2021

Cool, so we have the solution for EditFreeCampaign, now we need to find one for onboarding as well.

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

Successfully merging this pull request may close these issues.

3 participants