Skip to content

Instantly share code, notes, and snippets.

@sesteva
Created January 8, 2020 13:29
Show Gist options
  • Save sesteva/5af85534a4f46ae0614125b837d54b40 to your computer and use it in GitHub Desktop.
Save sesteva/5af85534a4f46ae0614125b837d54b40 to your computer and use it in GitHub Desktop.
Generated by XState Viz: https://xstate.js.org/viz
const CART_EVENT = {
ADD: "ADD",
REMOVE: "REMOVE",
UPDATE_QTY: "UPDATE_QTY",
SAVE_FOR_LATER: "SAVE_FOR_LATER"
};
const SAVE_FOR_LATER_EVENT = {
ADD_TO_LIST: "ADD_TO_LIST",
UNSAVE: "UNSAVE",
MOVE_TO_CART: "MOVE_TO_CART"
};
const addProduct = assign((ctx, evt) => {
const matches = ctx.cart.products.filter(i => i.id === evt.payload.id);
if (matches.length > 0) {
return {
cart: {
...ctx.cart,
products: ctx.cart.products.map(p => {
if (p.id === evt.payload.id) {
return {
...p,
qty: p.qty + 1
};
}
return p;
})
}
};
} else {
return {
cart: {
...ctx.cart,
products: [...ctx.cart.products, evt.payload]
}
};
}
});
const computeCartTotal = assign((ctx, evt) => {
const sumAllProductsQty = (acc, val) => acc + val.qty;
return {
cart: {
...ctx.cart,
count: ctx.cart.products.reduce(sumAllProductsQty, 0)
}
};
});
const removeProduct = assign((ctx, evt) => ({
cart: {
...ctx.cart,
products: ctx.cart.products.filter(p => {
if (p.id === evt.payload.id) {
return false;
}
return true;
})
}
}));
const updateProduct = assign((ctx, evt) => ({
cart: {
...ctx.cart,
products: ctx.cart.products.map(p => {
if (p.id === evt.payload.id) {
return {
...p,
...evt.payload
};
}
return p;
})
}
}));
const saveForLater = send((context, event) => ({
type: SAVE_FOR_LATER_EVENT.ADD_TO_LIST,
payload: event.payload
}));
const cartActions = {
addProduct,
computeCartTotal,
removeProduct,
updateProduct,
saveForLater
};
const addSaveForLater = assign((ctx, evt) => {
const matches = ctx.savedForLater.products.filter(
i => i.id === evt.payload.id
);
if (matches.length > 0) return ctx.savedForLater;
return {
savedForLater: {
...ctx.savedForLater,
products: [...ctx.savedForLater.products, evt.payload]
}
};
});
const unsaveProduct = assign((ctx, evt) => ({
savedForLater: {
...ctx.savedForLater,
products: ctx.savedForLater.products.filter(p => {
if (p.id === evt.payload.id) {
return false;
}
return true;
})
}
}));
const moveToCart = send((context, event) => ({
type: CART_EVENT.ADD,
payload: event.payload
}));
const saveForLaterActions = {
addSaveForLater,
unsaveProduct,
moveToCart
};
const guards = {
isCartEmpty: (ctx, evt) => ctx.cart.products.length < 1,
isSavedEmpty: (ctx, evt) => ctx.savedForLater.products.length < 1,
isProduct: (ctx, evt) => {
const p = evt.payload;
return p && p.id && p.id.length > 0; // add more validations
}
};
const cartMachine = Machine(
{
id: "cartMachine",
initial: "empty",
context: {
cart: {
count: 0,
products: [],
subtotal: 0,
delivery: 0,
estimatedTaxesAndFees: 0,
estimatedTotal: 0,
error: undefined
},
savedForLater: {
products: []
}
},
type: "parallel",
states: {
cart: {
id: "cart",
initial: "empty",
states: {
empty: {
on: {
[CART_EVENT.ADD]: {
target: "unpaid",
actions: ["addProduct", "computeCartTotal"],
cond: "isProduct"
}
}
},
unpaid: {
initial: "normal",
on: {
"": {
target: "empty",
cond: "isCartEmpty"
},
[CART_EVENT.SAVE_FOR_LATER]: {
actions: ["saveForLater", "removeProduct", "computeCartTotal"]
},
[CART_EVENT.REMOVE]: {
target: ".normal",
actions: ["removeProduct", "computeCartTotal"],
cond: "isProduct"
},
[CART_EVENT.ADD]: {
target: ".normal",
actions: ["addProduct", "computeCartTotal"],
cond: "isProduct"
},
[CART_EVENT.UPDATE_QTY]: {
target: ".normal",
actions: ["updateProduct", "computeCartTotal"],
cond: "isProduct"
},
UPDATE_PRICE: {
target: ".normal",
actions: "updateProduct",
cond: "isProduct"
},
PAY: "paying"
},
states: {
error: {},
normal: {}
}
},
paying: {
on: {
RESOLVE: "paid",
REJECT: "unpaid.error"
}
},
paid: {
after: {
1000: "empty"
}
}
}
},
savedForLater: {
id: "savedForLater",
initial: "empty",
on: {
[SAVE_FOR_LATER_EVENT.ADD_TO_LIST]: {
target: ".saved",
actions: ["addSaveForLater"]
}
},
states: {
empty: {},
saved: {
on: {
"": {
target: "empty",
cond: "isSavedEmpty"
},
[SAVE_FOR_LATER_EVENT.UNSAVE]: {
actions: ["unsaveProduct"]
},
[SAVE_FOR_LATER_EVENT.MOVE_TO_CART]: {
actions: ["moveToCart", "unsaveProduct"]
}
}
}
}
}
}
},
{
actions: {
...cartActions,
...saveForLaterActions
},
guards
}
);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment