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

Dues estimator to reduce currencylayer usage #10767

Open
wants to merge 2 commits into
base: main
Choose a base branch
from

Conversation

danieljames-dj
Copy link
Member

For getting currency details, we moved to currencylayer API which is paid. Currently, the dues is shown on competition edit page, but it may not be noticed every time by the user. So it has been replaced with a button now as shown below:

Screenshot 2025-02-04 at 06 33 28

When the user clicks the button, they will be able to see the dues estimate. This view not only shows the dues estimate, but also allows user to change the competitor count temporarily and see what is the dues for that competitor count:

Screenshot 2025-02-04 at 06 35 50

The future plan of this component will be to explain the dues calculation method used in this component, so that delegate can easily understand it from here, and hence reduce queries to WFC on 'why is the dues xyz for n competitors'.

import Errored from '../../Requests/Errored';
import { fetchJsonOrError } from '../../../lib/requests/fetchWithAuthenticityToken';

const CALCULATE_DUES_QUERY_CLIENT = new QueryClient();
Copy link
Contributor

Choose a reason for hiding this comment

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

Usually we wrap the component in a query client. I don't really know what the difference is though.

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'm not sure which is the way to be followed. I followed this way because this is how I did in my first use-query implementation of this repo, and I think I copied this way from somewhere else in the same repo.

Please let me know if this needs to be changed, I'm totally fine with switching if the other method is better.

Looking forward for the opinion of @gregorbg too.

Copy link
Member

Choose a reason for hiding this comment

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

We wrap it everywhere we can. To my knowledge, there is one instance of a const client being passed around, which is WcaSearch (and IdWcaSearch in the same file). That's because these are form components where we cannot be sure in which contexts they are used, and under what circumstances a client may or may not be available.

Copy link
Member

Choose a reason for hiding this comment

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

In your case, you are not providing an "entry point" component that is injected into our frontend with react_component. So having it this way is fine.

In the future, when you're working with components which are intended to be "entry points" for our Rails erb code using react_component, then you should definitely wrap in a client provider.

const {
data, isLoading, isError,
} = useQuery({
queryKey: ['calculateDues'],
Copy link
Contributor

Choose a reason for hiding this comment

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

Does this work? The keys need to include everything that the query depends on. Otherwise, if the query is re-run with a different say base entry fee, then it will retrieve the previous cached data (based on the previous base entry fee), since the keys match. I think.

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 for that. I've changed it, I'm pretty new to useQuery so didn't knew the theory much.

Apparently this was working with constant queryKey as well apparently. I changed the registration fees and opened the component again, and the output is different, and not from cached. I'm not sure why, maybe in local there is no cache.

Copy link
Contributor

Choose a reason for hiding this comment

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

I think that since the query client is re-created every time the component is first rendered (since it's defined in the dues estimate file rather than wrapping the entire form), so it's a fresh instance with no cache each time? And you can't change any of the keys without first closing the component and then re-opening it fresh.

Generally, I think the best approach is a single query client at the root of the app, but we can't do that since rails is rendering react components individually, so we don't have a single root in the react world (if I understand correctly).

Copy link
Member Author

Choose a reason for hiding this comment

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

That makes sense. I guess these will be changed after the nextJS integration.

render json: {
dues_value: total_dues.present? ? total_dues.format : nil,
dues_value: per_competitor_dues.to_f,
Copy link
Member

Choose a reason for hiding this comment

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

Why are you converting this to a float?

Copy link
Member

Choose a reason for hiding this comment

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

Or to be precise, why are you converting this to a float here? Communicating floating point numbers is always dangerous because of rounding errors, overflows, etc. If the money library provides an integer return value by default, it probably does so for a good reason.

If you want to display an float-like value (with decimal point) to the user, then you are of course free to do so. But the conversion from int to float should only happen immediately before you display it in the frontend.

Copy link
Member Author

Choose a reason for hiding this comment

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

Okay, I'm now passing the lowest denomination value and converting it in the frontend. Hope this works.

import Errored from '../../Requests/Errored';
import { fetchJsonOrError } from '../../../lib/requests/fetchWithAuthenticityToken';

const CALCULATE_DUES_QUERY_CLIENT = new QueryClient();
Copy link
Member

Choose a reason for hiding this comment

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

We wrap it everywhere we can. To my knowledge, there is one instance of a const client being passed around, which is WcaSearch (and IdWcaSearch in the same file). That's because these are form components where we cannot be sure in which contexts they are used, and under what circumstances a client may or may not be available.

import Errored from '../../Requests/Errored';
import { fetchJsonOrError } from '../../../lib/requests/fetchWithAuthenticityToken';

const CALCULATE_DUES_QUERY_CLIENT = new QueryClient();
Copy link
Member

Choose a reason for hiding this comment

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

In your case, you are not providing an "entry point" component that is injected into our frontend with react_component. So having it this way is fine.

In the future, when you're working with components which are intended to be "entry points" for our Rails erb code using react_component, then you should definitely wrap in a client provider.

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