How to increase, decrease and eliminate items in cart? - e-commerce

My function to add items to the cart works fine. However, once I'm inside the cart, i want to be able to increase and decrease the quantity of the items, or being able to eliminate them.
I already added the necessary buttons to each item that gets added to the cart (a "+" and "-" button, and "Delete item" button).
I have an array "products[ ]" with the info: name, price, id, and quantity.
for (const decrease of buttonDecrease) {
decrease.addEventListener("click", ()=> { products.quantity -= 1;
});
}
let buttonIncrease = document.querySelectorAll("#increase");
for (const increase of buttonIncrease) {
increase.addEventListener("click", ()=> { products.quantity += 1;
});
}```
If it helps for context, i add the items to the cart with:
let button = document.querySelectorAll(".cartButton");
for (const cartButton of button) {
cartButton.addEventListener("click", ()=> {
let product = productss.find(products => products.id == cartButton.id);
cat.push(producto)
localStorage.setItem("cart", JSON.stringify(cart))
});
}
}
loadEvents();```

Related

How to open open card and verify the content inside then open the second card and verify the content and so on

I need to open the first card and verify that everything inside matches the hashtag 'Fashion' and then do the same for the next 3 cards and then press the 'next' button and do the same for next 4 cards. how would I do it? I tried the regular way by clicking on the element.eq(0) and verifying everything inside and then cy.go('back') and so on but that's so much code duplication. how would I do it the other way?
First 4 cards:
Second 4 cards:
The CSS selector for all of them is the same [class="discover-card"]. please help:) thank you
You can use Cypress's .each() functionality to iterate through elements with the same CSS selector.
cy.get('.discover-card').each(($card, index) => {
// cy.go('back') can cause the list to become detached, so find element by index of original list.
cy.get('.discover-card').eq(index).click();
// validations after clicking the card
// unsure on this exact function, but was provided in question
cy.go('back').then(() => {
// if this is the fourth item checked, we need to press the next button.
if ((index + 1) % 4 === 0) {
cy.get('.next-btn').click(); // this selector is the next button on the carousel
}
});
});
If the data between the cards is unique, I'd advise creating a data object you can use to store the data and reference it in your test. You can do this by having each data object have a unique key equal to the text on the card, or by storing them in an array.
// unique keys
const data = { fashion: { foo: 'bar' }, beauty: { foo: 'bar2' }, ... };
// array
const data = [{ foo: 'bar' }, { foo: 'bar2' }, ...];
...
// unique keys
cy.wrap($card).should('have.attr', 'foo', data[$card.text()].foo);
// array
cy.wrap($card).should('have.attr', 'foo', data[index].foo);
If you are concerned about code duplication, put the common code in a function
const expectedData [
{ index: 1, title:'Fashion', ... } // anything you want to check
{ index: 2, title:'Beauty', ... }
]
const checkCard = (cardIndex) => {
const data = expectedData[cardIndex]
cy.get('.discover-card')
.should('contain', data.title)
.click() // open card
// test card internals
}
Cypress._.times(3, (pageNo) => { // loop 3 times between pages
Cypress._.times(4, (cardNo) => { // loop 4 times for cards
const cardIndex = ((pageNo+1) * (cardNo+1)) -1
checkCard(cardIndex)
cy.go.back() // revert to menu
})
cy.get('.next-btn').click()
})

Scroll to a programmatically selected row in a v-data-table

I have a map with features on it that are also listed in a v-data-table. When the user clicks a row, the feature is highlighted on the map. When the user clicks a map feature, the corresponding grid row is selected. So I am programmatically setting the selected row like this:
selectRow(id) {
this.selected = [this.getRowFromId(id)]
},
getRowFromId(id) {
for (let site of this.sites) {
if (site.id === id) return site;
}
return []
},
Works fine with one UX problem: The table is not scrolled to the selected row.
I am using a vertically scrolling data-table with all rows in the grid rather than pagination.
Any ideas on how to programmatically scroll the data table?
Here is my solution. I found most of what I was looking for in this post: Plain JavaScript - ScrollIntoView inside Div
I had to do a couple of v-data-grid specific things to make it work. I am using a watcher in my context but you could to this anywhere you needed to:
watch: {
selectedId: function(newVal) { // watch it
// Select the row
this.selectRow(newVal)
// Scroll the item into view
// First we need to let the component finish selecting the row in the background
setTimeout( () => {
// We get the selected row (we assume only one or the first row)
const row = document.getElementsByClassName("v-data-table__selected")[0]
// Then we get the parent. We need to give the -v-data-table a ref
// and we actually take the child of the table element which
// has the scrollbar in my case.
const parent = this.$refs.detailGrid.$el.firstChild
// Finally call the scroll function
this.scrollParentToChild(parent, row )
}, 100)
}
},
methods: {
scrollParentToChild(parent, child) {
// Where is the parent on page
var parentRect = parent.getBoundingClientRect();
// What can you see?
var parentViewableArea = {
height: parent.clientHeight,
width: parent.clientWidth
};
// Where is the child
var childRect = child.getBoundingClientRect();
// Is the child viewable?
var isViewable = (childRect.top >= parentRect.top) && (childRect.top <= parentRect.top + parentViewableArea.height);
// if you can't see the child try to scroll parent
if (!isViewable) {
// scroll by offset relative to parent
parent.scrollTop = (childRect.top + parent.scrollTop) - parentRect.top - childRect.height
}
},
}

Update cart item number instead of appending new item

If an already added product is again added to the cart then only cart number should increase but the function appends the data to the list and the product gets duplicate in the cart view. How to make sure check if the product already exists then only increment or decrement the count.
below is the code to update product
const initialState = {
cart: [],
total: 0,
}
const cartItems = (state = initialState, action) => {
switch(action.type) {
case 'ADD_TO_CART':
return {
...state,
cart: [action.payload, ...state.cart],
total: state.total + 1
}
// return [...state,action.payload]
case 'REMOVE_FROM_CART' :
return state.filter(cartItems => cartItems.id !== action.payload.id)
}
return state
}
A single item from the data will be like
{key:'1', type:"EARRINGS", pic:require('../../assets/earring.jpg'),price:"200"}
If you are using the same key for the items you can do like below
case 'ADD_TO_CART':
{
const updatedCart = [...state.cart];
const item = updatedCart.find(x=>x.key===action.payload.key);
if(item)
{
item.count++;
}
else{
updatedCart.push(action.payload);
}
return {
...state,
cart: updatedCart,
total: state.total + 1
}
}
The logic would search for items in the array and increase the count or add a new item to the array.
I think this will work.
case UPDATE_CART:
let receivedItem = action.payload
let itemList = state.cart
let stepToUpdate = itemList.findIndex(el => el.id === receivedItem.id);
itemList[stepToUpdate] = { ... itemList[stepToUpdate], key: receivedItem };
return { ...state, cart: itemList }
'id' is a unique thing to update specific item present in your cart. It cab be product id or some other id.
itemList.findIndex(el => el.id === receivedItem.id);
There are different ways of achieving this. You can create actions to INCREMENT/DECREMENT in case you know the product is added (eg: on the cart summary).
And you can also let this behaviour inside the ADD_TO_CART action if you don't know whether the product is added or not:
case "ADD_TO_CART": {
const isProductAdded = state.cart.find(
item => action.payload.id === item.id
);
return {
...state,
cart: isProductAdded
? state.cart.map(item => {
if (item.id === action.payload.id) {
item.qty++;
}
return item;
})
: [action.payload, ...state.cart],
total: state.total + 1
};
}

React Native Redux - How to delete one item at a time

I'm creating a react native application for e-commerce purposes and am trying to get the cart functionality working. I'm using redux and I am able to add one item at a time to the cart but when I try to delete an item from the cart, all of the same items get deleted. For example, if I have 2 pencils, 3 pens and 4 notebooks in my cart and I click the delete button on one of the notebooks, all 4 notebooks get removed from my cart. I want to be able to only remove one item at a time.
const cartItems = (state = [], action) => {
switch (action.type) {
case 'ADD_TO_CART':
return [...state, action.payload]
case 'REMOVE_FROM_CART':
return state.filter(cartItem => cartItem.id !== action.payload.id)
//return state.filter(cartItem => cartItem !== action.payload.id
//const filteredItems = state.filter((cartItem) => cartItem.id !== action.payload.id);
}
return state
}
export default cartItems
The two lines that are commented out are the other ways I've tried, but ultimately didnt work.
This line
return state.filter(cartItem => cartItem.id !== action.payload.id)
Means "return a new array consisting of all state elements except those which have id property matching action.payload.id".
So if there are multiple items with the same id, all f them will be filtered out.
Since this is just plain JavaScript, you can have any logic here, you just need to return a new array. This, for example, will delete only the first matching element:
let removed = false;
return state.filter(cartItem => {
if (cartItem.id === action.payload.id && !removed) {
removed = true;
return false;
}
return true;
});
A better solution would be to create another identifier for the items in cart, so that the action does not remove the first matching item in the list, but the one the user requested to delete by tapping the delete button.

Ext JS 4.1 get column index in itemcontextmenu

When I add listener for itemcontextmenu for Grid/Tree I'm able to access view record, item, index, but how to get column?
What I want to create is a contextMenu but only if user click on items in first column.
Here is my listener function:
firstColumnContext: function(view,record,item,index,e,eOpts) {
console.log(view);
console.log(record.getName());//this works
console.log(index);
console.log('get column');//
},
My concept looks like this:
firstColumnContext: function(view,record,item,index,e,eOpts) {
e.stopEvent();
if(record.get('leaf') && 'first column')
{
//show context menu here
}
},
But as I wrote before I need to verify if rightclick was in first column.
See this code, setup your grids viewConfig like this:
viewConfig: {
listeners:{
beforecellcontextmenu: function(view, tableCell, columnIndex, record, tableRow, rowIndex){
//your menu code here
},
itemcontextmenu: function(view,record,item,index,e,eOpts){
e.stopEvent();
}
}
}
The column index is provided by the beforecellcontextmenu event but not the fired event does not provide the event itself, so you have to use a combination of both events, one to stop the default menu and the other to pop it up in the case you want it to show.
I had this problem too. Here is the hack I devised for Grids that works nicely. It compares the mouse position at click to the positions of each column and finds when they overlap.
grid.on('itemcontextmenu', function(view, record, item, index, e) {
var xPos = e.getXY()[0];
var cols = view.getGridColumns();
for(var c in cols) {
var leftEdge = cols[c].getPosition()[0];
var rightEdge = cols[c].getSize().width + leftEdge;
if(xPos>=leftEdge && xPos<=rightEdge) {
console.log(cols[c].dataIndex);
}
}
});