Why map.containsKey(object) doesn't works when refresh page on Flutter web? - dictionary

Currently i have a cart application and use hive package to save data cart on memory.
When i use normally the app, the quantity of cart show properly grouped.
These is the code for deduplicate the items and show their quantity grouped
Map productsQuantity(List<Product> localProducts) {
var result = {};
for (var singleProduct in localProducts) {
if (!result.containsKey(singleProduct)) {
result[singleProduct] = 1;
} else {
result[singleProduct] += 1;
}
}
return result;
}
It's works fine ... but when i refresh the page the items are ungrouped
Before refresh the page, the cart show 5 items and this is expected
2 items of X product
3 items of Y product
After refresh this is the output:
1 item X
1 item X
1 item Y
1 item Y
1 item Y

Related

Saleor Shopping Cart Sometimes Wrong/Older Version - Using GraphQL and Next.js

I am using Saleor shopping cart GraphQL, and actually Stepzen to merge it with a Strapi GraphQL. So all Saleor mutations and queries go through the Stepzen GraphQL.
I have followed Saleors tutorial here:
https://learn.saleor.io/checkout/displaying-cart-content/
This works 90% of the time so generally the code should be OK, but I must be missing something because occasionally when adding to the cart the contents are different. The item is not added. In fact, it's possible the cart seen is an older version but am not sure. I could add to cart 4 times and it updates to the correct products and quantities each time, then the 5th time it shows the cart from the last time or even time before.
After a few seconds, if you refresh the page, the cart displays correct.
EDIT: I have just noticed, if you refresh the page several times, the cart sometimes changes, and a refresh changes back, then a refresh it changes to something else and just keeps changing on refreshes!
When the cart works, there is a little delay adding it, but when it doesn't work the cart page loads much faster, almost instantly. It's as if when it works it waits for Saleors response for the cart items list, but when it doesn't it doesn't wait for the response. Just a hunch.
This is my query code to get cart items from Saleor. It does work, 90% of the time.
const Cart = () => {
const [token] = useCookies('["token"]')
const { data, loading, error } = useCheckoutFetchByTokenQuery({
variables: { checkoutToken: token.token },
skip: !token.token,
});
const [CheckoutremoveProduct] = useCheckoutRemoveProductMutation();
if (loading) return <div>Loading...</div>;
if (error) return <div>Error</div>;
if (!data || !data.saleorcheckout) return null;
const products = data.saleorcheckout?.lines || [];
return (
<Layout title="Cart">
.....
</Layout>
);
}
The actual saleorcheckout query:
query CheckoutFetchByToken($checkoutToken: saleorUUID!) {
saleorcheckout(token: $checkoutToken) {
id
email
lines {
id
quantity
totalPrice {
gross {
amount
currency
}
}
variant {
id
product {
id
name
slug
thumbnail {
url
alt
}
cmsContent {
SaleorID
Title
Featured_image
{
data
{
attributes
{
url
width
height
alternativeText
}
}
}
}
}
pricing {
price {
gross {
amount
currency
}
}
}
name
}
}
totalPrice {
gross {
amount
currency
}
}
}
}
Interestingly the saleorcheckoutLinesAdd mutation which adds lines to the cart returns with the correct products in the cart, after the new one is added, but on the cart page that uses saleorcheckout to fetch them returns a lower amount, until you refresh later.
The actual saleorcheckoutLinesAdd mutation:
mutation ProductAddVariantToCart($checkoutToken: saleorUUID!, $variantId: ID!) {
saleorcheckoutLinesAdd(
token: $checkoutToken
lines: [{ quantity: 1, variantId: $variantId }]
) {
checkout {
id
lines {
id
quantity
variant {
id
name
product {
name
}
}
}
}
errors {
message
}
}
}
Thanks
UPDATE:
My first post above included this below, but it may be a red herring as I have added the variant ID in the query now, and dont get this error below anymore, but the problem above still exists.
Previously when it doesn't work the following error was in console:
react_devtools_backend.js:4026 Cache data may be lost when replacing the variant field of a saleorCheckoutLine object.
To address this problem (which is not a bug in Apollo Client), either ensure all objects of type saleorProductVariant have an ID or a custom merge function, or define a custom merge function for the saleorCheckoutLine.variant field, so InMemoryCache can safely merge these objects:
existing: {"__typename":"saleorProductVariant","product":{"__ref":"saleorProduct:UHJvZHVjdDoxNjY="},"pricing":{"__typename":"saleorVariantPricingInfo","price":{"__typename":"saleorTaxedMoney","gross":{"__typename":"saleorMoney","amount":100,"currency":"USD"}}},"name":"UHJvZHVjdFZhcmlhbnQ6NDAy"}
incoming: {"__typename":"saleorProductVariant","name":"UHJvZHVjdFZhcmlhbnQ6NDAy","product":{"__typename":"saleorProduct","name":"52-00 Base Plate"}}
I have looked this up, and the solution is to set typePolicies the ApolloClient to state to merge the new and old carts. BUT I cannot get this to work, if it is the solution. Online some examples of typePolicies and merge have console.log() outputs but mine are just not firing. So I am assuming I have not set the typePolicies up correct perhaps.
This is my typePolicies code, although I have tried many variations, and the fact lines is nested may be complicating it.
const client = new ApolloClient({
uri: "https://my-stepzen-graphql-url.com/__graphql",
cache: new InMemoryCache({
typePolicies: {
Query: {
fields: {
saleorcheckoutLinesAdd: {
lines: {
merge(existing, incoming, { mergeObjects }) {
console.log(existing)
console.log(incoming)
return mergeObjects(existing, incoming);
},
},
},
},
},
},
}),
})
I have tried many versions of the above typePolicies, but can never get console.log to fire, so assume I have fond the correct format.

Installment widget - Wordpress + Woocommerce

What's the problem?
I want to add a PayU plugin installment widget for a product subpage for WooCommerce, but I have a problem with displaying the product price in the calculator provided in the documentation.
Code source for implementing such a calculator:
https://developers.payu.com/en/installments.html#installments_best_practices_mini
<p><span id="installment-mini"></span></p>
<script type="text/javascript">
var value = 1234.56;
if (value >= 300 && value <= 50000) {
var options = {
creditAmount: value,    // amount in PLN
posId: '67328',         // point of sale identifier
key: 'zQ',              // first two characters of API key
showLongDescription: true
};
  OpenPayU.Installments.miniInstallment('#installment-mini', options)
.then(function(result) {
// This fragment of code will be executed after widget is shown
// parameter ‘result’ contains additional functions
})
.catch(function(e) {
console.error(e.toString()); // This snippet writes config errors
// to developer’s console
});
}
What do i want to get?
I want only the product price in the product card to be downloaded to the installment calculator. There is no input field in the product card, only , I thought about a positive in the php code but it did not work. I want to add a regular price or the price of a product variant to the JS code to show the customer what he can do when choosing installments, so the price must be taken to the code above.

Meteor js custom pagination

I kindly need a support. I have written a pagination following a YouTube tutorial, which works fine with the exception of when going backwards again. It has only 2 buttons, previous and next, when the next button is clicked it works fine but the previous button only go backwards once. Let's say I have 20 records in the collections paginated to display 5 at a time, the next button could go to the end to the fourth page but the previous button would not go pass one step backwards. Please what am I to do to have pagination experience? The previous button is suppose to navigate to the last page as long as the user clicks.
Events for the pagination buttons:
Template.myviews.events({
'click .previous': function () {
if (Session.get('skip') > 5 ) {
Session.set('skip', Session.get('skip') - 5 );
}
},
'click .next': function () {
Session.set('skip', Session.get('skip') + 5 );
}
});
Publication:
Meteor.publish('userSchools', function (skipCount) {
check(skipCount, Number);
user = Meteor.users.findOne({ _id: this.userId });
if(user) {
if(user.emails[0].verified) {
return SchoolDb.find({userId: Meteor.userId()}, {limit: 5, skip: skipCount});
} else {
throw new Meteor.Error('Not authorized');
return false;
}
}
});
Subscription:
Session.setDefault('skip', 0);
Tracker.autorun(function () {
Meteor.subscribe('userSchools', Session.get('skip'));
});
Blaze pagination buttons:
<ul class="pager">
<li class="previous">Previous </li>
<li class="next">Next </li>
</ul>
Template helper:
RenderSchool: function () {
if(Meteor.userId()) {
if(Meteor.user().emails[0].verified) {
return SchoolDb.find({userId: Meteor.userId()}).fetch().reverse();
} else {
FlowRouter.go('/');
Bert.alert('Please verify your account to proceed', 'success', 'growl-top-right');
}
}
}
You have 6 documents total with 2 docs per page, 3 pages in total.
Your if condition in previous button click handler prevents you from going to the first page:
if (Session.get('skip') > 2 /* testing */ ) {
...
}
For 2nd page skip will equal 2 and on the next click this condition will be false, preventing from going back.
When you're on the 3rd page — you can go on 2nd only, creating an impression that button works only once.
It should be like this:
if (Session.get('skip') > 0 ) {
...
}

How to use a static range and display members according a TOP(x) style query

We are trying to add a slider jquery widget, and would like to define a static range, say percentage from 0% to 100%.
Then we would like to use the value from the slider in that range as the parameter for the TOP(x), as shown on the picture.
Is this possible?
Any hints ?
I've created an example report for you, import it using the default [Sales] schema
https://drive.google.com/file/d/0B3kSph_LgXizdk9OdnlTWkxHa1U/view?usp=sharing
You could achieve this functionality by using the next sequence:
Create Slider widget
Open a widget options dialog and configure widget properties
Select Query Wizard -> Query Type: Mdx Hierarchies
Add single random hierarchy to bypass validation(it will be replaced)
Setup the default value in Initial Selection (i.e. 10%)
Add a code to your report javascript
viz.filters.Slider.prototype.componentWillMount = function(){
if(_.isArray(this.props.items))
this.setState({
entities:new viz.EntityData(this.props.items),
range:_.map(this.props.defaults,"uniqueName")
});
}
viz.filters.Slider.prototype.onBuildAllDone = function(){
if(!_.isEmpty(this.state.range)) {
this.fireEvent(vizEventType.onSelection,
this.createEvent(this.state.range));
this.fireEvent(vizEventType.onNewLabel,
this.createEvent(this.state.range));
}
}
function consumeEvent( context, event ) {
if (event.name == 'ic3-report-init') {
// Following code will replace a data provider for Slider
// with generated numbers. But to do so, you'll need UID of
// the Slider widget, in this example it's "w1"
var widget = event.value.widgetMgr().getItemById("w1");
_.assign(widget.builder().guts_, {
items:_.times(100, function(idx){
return {
name:idx + 1 + "%",
uniqueName:idx + 1
}
})})
}
}

Meteor Filter Data in List by Clicking on Sidebar Categories

I have a list of categories that appear in a sidebar (for instance: food, toys, clothes, etc.).
In the content I have a list of items each of which belong to a category. I want a user to be able to sort that list by clicking on the appropriate category in the sidebar.
For instance, if they click solely on Food then only items from the food category will appear. If they ALSO click on Toys then items from BOTH the food and toys category will appear.
How can I set this up?
Thanks.
You can do something like this:
Template.filters.onCreated(function () {
this.filters = new ReactiveVar({});
});
Template.filters.helpers({
categories: function () {
const instance = Template.instance();
return Categories.find(instance.filters.get());
}
});
Template.filters.events({
// whenever a select is changed
'change select.category-filter': function (e, template) {
const categories = $(e.target).find('option:checked').reduce(function (query, node) {
query[node.data.name] = this.value;
return query;
}, {});
template.filters.set(categories);
}
});
The reactive var will change, updating the helper, and in turn updating the query.

Resources