Skip to content

Commit

Permalink
Adding undo to the cart
Browse files Browse the repository at this point in the history
  • Loading branch information
cesarParra committed May 31, 2024
1 parent 696769c commit a10f96f
Show file tree
Hide file tree
Showing 6 changed files with 135 additions and 71 deletions.
1 change: 0 additions & 1 deletion .prettierrc
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
{
"trailingComma": "none",
"plugins": [
"prettier-plugin-apex",
"@prettier/plugin-xml"
],
"overrides": [
Expand Down
37 changes: 30 additions & 7 deletions examples/demo-signals/lwc/demoSignals/shopping-cart.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@ import { $resource } from "c/signals";
import getShoppingCart from "@salesforce/apex/ShoppingCartController.getShoppingCart";
import updateShoppingCart from "@salesforce/apex/ShoppingCartController.updateShoppingCart";

/**
* @typedef {Object} ShoppingCart
* @property {Item[]} items
*/

/**
* @typedef {Object} Item
* @property {string} id
Expand All @@ -13,29 +18,47 @@ import updateShoppingCart from "@salesforce/apex/ShoppingCartController.updateSh
* @property {number} imgUrl
*/

// Store each state change in the cart history
const cartHistory = [];
let isUndoing = false;

export function undoCartChange() {
isUndoing = true;
const lastState = cartHistory.pop();
if (lastState) {
updateCart(lastState);
}
isUndoing = false;
}

/**
* Updates the cart on the server
* @param {Item[]} newCart
* @param _
* @param {ShoppingCart} newCart
* @param {ShoppingCart} previousValue
* @param mutate
*/
async function updateCartOnTheServer(newCart, _, mutate) {
// Quantities can be updated, so gather the Ids and quantities and check
// if the quantities have changed. Note that only one item can be updated
// at a time in this example.
async function updateCartOnTheServer(newCart, previousValue, mutate) {
try {
// Update the cart on the server
const updatedShoppingCart = await updateShoppingCart({
newItems: newCart.items
});

// Update the local state with the new cart received from the server
mutate(updatedShoppingCart);

// Store the previous value in the history
if (!isUndoing) {
cartHistory.push(previousValue);
}
} catch (error) {
mutate(null, error);
}
}

// TODO: When we document this, remember there are 2 options. We can either
// do the update the same way we are doing it here (through onMutate) or
// it can be done in the component and then `refetch` can be called.
// it can be done in the component (or anywhere really) and then `refetch` can be called.

export const { data: shoppingCart, mutate: updateCart } = $resource(
getShoppingCart,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ public with sharing class ShoppingCartController {
@AuraEnabled
public static ShoppingCartDto updateShoppingCart(List<ItemDto> newItems) {
// This is just for example purpose, in a real-world scenario, you would update the shopping cart in the database
System.debug('New items: ' + newItems);
return new ShoppingCartDto(newItems);
}

Expand All @@ -25,7 +24,7 @@ public with sharing class ShoppingCartController {
@AuraEnabled public List<String> properties { get; set; }
@AuraEnabled public Integer quantity { get; set; }
@AuraEnabled public Decimal price { get; set; }
@AuraEnabled public Decimal taxAmount { get { return (price * quantity) * TAX_RATE; } }
@AuraEnabled public Decimal taxAmount { get {return (price * quantity) * TAX_RATE;} }
@AuraEnabled public String imgUrl { get; set; }

// No arg constructor so it can be built from JSON
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import TwElement from "c/twElement";
import { $computed } from "c/signals";
import { shoppingCart, updateCart } from "c/demoSignals";
import { shoppingCart, updateCart, undoCartChange } from "c/demoSignals";

// States
import ready from "./states/ready.html";
Expand Down Expand Up @@ -55,4 +55,8 @@ export default class ShoppingCartDetails extends TwElement {
});
updateCart({ items: newItems });
}

undo() {
undoCartChange();
}
}
152 changes: 96 additions & 56 deletions examples/shopping-cart/lwc/shoppingCartDetails/states/ready.html
Original file line number Diff line number Diff line change
@@ -1,61 +1,101 @@
<template>
<div class="mx-auto max-w-4xl px-4">
<h1 class="text-3xl font-bold tracking-tight text-gray-900">Shopping Cart</h1>
<div>
<h2 class="sr-only">Items in your shopping cart</h2>
<div class="mx-auto max-w-4xl px-4">
<h1 class="text-3xl font-bold tracking-tight text-gray-900">
Shopping Cart
</h1>
<div>
<h2 class="sr-only">Items in your shopping cart</h2>
<button
class="mt-4 text-sm font-medium text-indigo-600 hover:text-indigo-500"
type="button"
onclick={undo}
>
Undo last change
</button>
<ul
role="list"
class="divide-y divide-gray-200 border-b border-t border-gray-200"
>
<template for:each={items} for:item="item">
<li key={item.id} class="flex py-6 sm:py-10">
<div class="flex-shrink-0">
<img
src={item.imgUrl}
alt={item.name}
class="h-24 w-24 rounded-lg object-cover object-center sm:h-32 sm:w-32"
/>
</div>
<div
class="relative ml-4 flex flex-1 flex-col justify-between sm:ml-6"
>
<div>
<div class="flex justify-between sm:grid sm:grid-cols-2">
<div class="pr-6">
<h3 class="text-sm">
<a
href="#"
class="font-medium text-gray-700 hover:text-gray-800"
>{item.name}</a
>
</h3>
<template for:each={item.properties} for:item="property">
<p key={property} class="mt-1 text-sm text-gray-500">
{property}
</p>
</template>
</div>
<p class="text-right text-sm font-medium text-gray-900">
<lightning-formatted-number
value={item.total}
format-style="currency"
currency-code="USD"
></lightning-formatted-number>
</p>
</div>

<ul role="list" class="divide-y divide-gray-200 border-b border-t border-gray-200">
<template for:each={items} for:item="item">
<li key={item.id} class="flex py-6 sm:py-10">
<div class="flex-shrink-0">
<img src={item.imgUrl} alt={item.name} class="h-24 w-24 rounded-lg object-cover object-center sm:h-32 sm:w-32">
</div>
<div class="relative ml-4 flex flex-1 flex-col justify-between sm:ml-6">
<div>
<div class="flex justify-between sm:grid sm:grid-cols-2">
<div class="pr-6">
<h3 class="text-sm">
<a href="#" class="font-medium text-gray-700 hover:text-gray-800">{item.name}</a>
</h3>
<template for:each={item.properties} for:item="property">
<p key={property} class="mt-1 text-sm text-gray-500">{property}</p>
</template>
</div>
<p class="text-right text-sm font-medium text-gray-900">
<lightning-formatted-number value={item.total} format-style="currency" currency-code="USD"></lightning-formatted-number>
</p>
</div>
<div
class="mt-4 flex items-center sm:absolute sm:left-1/2 sm:top-0 sm:mt-0 sm:block"
>
<lightning-select
data-item={item.id}
name="tickets"
label="How many tickets?"
value={item.quantity}
options={quantityOptions}
onchange={handleQuantityChange}
required
></lightning-select>
<lightning-button
variant="base"
data-item={item.id}
onclick={removeItem}
type="button"
class="ml-4 text-sm font-medium text-indigo-600 hover:text-indigo-500 sm:ml-0 sm:mt-3"
label="Remove"
>
</lightning-button>
</div>
</div>

<div class="mt-4 flex items-center sm:absolute sm:left-1/2 sm:top-0 sm:mt-0 sm:block">
<lightning-select
data-item={item.id}
name="tickets"
label="How many tickets?"
value={item.quantity}
options={quantityOptions}
onchange={handleQuantityChange}
required ></lightning-select>
<lightning-button
variant="base"
data-item={item.id}
onclick={removeItem}
type="button"
class="ml-4 text-sm font-medium text-indigo-600 hover:text-indigo-500 sm:ml-0 sm:mt-3"
label="Remove">
</lightning-button>
</div>
</div>

<p class="mt-4 flex space-x-2 text-sm text-gray-700">
<svg class="h-5 w-5 flex-shrink-0 text-green-500" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
<path fill-rule="evenodd" d="M16.704 4.153a.75.75 0 01.143 1.052l-8 10.5a.75.75 0 01-1.127.075l-4.5-4.5a.75.75 0 011.06-1.06l3.894 3.893 7.48-9.817a.75.75 0 011.05-.143z" clip-rule="evenodd" />
</svg>
<span>In stock</span>
</p>
</div>
</li>
</template>
</ul>
</div>
<p class="mt-4 flex space-x-2 text-sm text-gray-700">
<svg
class="h-5 w-5 flex-shrink-0 text-green-500"
viewBox="0 0 20 20"
fill="currentColor"
aria-hidden="true"
>
<path
fill-rule="evenodd"
d="M16.704 4.153a.75.75 0 01.143 1.052l-8 10.5a.75.75 0 01-1.127.075l-4.5-4.5a.75.75 0 011.06-1.06l3.894 3.893 7.48-9.817a.75.75 0 011.05-.143z"
clip-rule="evenodd"
/>
</svg>
<span>In stock</span>
</p>
</div>
</li>
</template>
</ul>
</div>
</div>
</template>
7 changes: 3 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
"test:coverage": "jest --coverage",
"create:scratch": "sf org create scratch --alias lwc-signals --definition-file config/project-scratch-def.json --set-default",
"dev:start": "npm run create:scratch && sf project deploy start",
"lint": "eslint **/{aura,lwc}/**/*.js",
"lint": "eslint ./{examples,force-app,src}/**/{lwc}/*.{js,ts} --no-error-on-unmatched-pattern",
"prettier": "prettier --write \"**/*.{cls,cmp,component,css,html,js,json,md,page,trigger,xml,yaml,yml}\"",
"prettier:verify": "prettier --check \"**/*.{cls,cmp,component,css,html,js,json,md,page,trigger,xml,yaml,yml}\"",
"postinstall": "husky install",
Expand All @@ -33,7 +33,6 @@
"jest-environment-jsdom": "^29.7.0",
"lint-staged": "^15.1.0",
"prettier": "^3.1.0",
"prettier-plugin-apex": "^2.0.1",
"ts-jest": "^29.1.2",
"ts-node": "^10.9.2",
"typescript": "^5.4.5",
Expand All @@ -42,10 +41,10 @@
"@tailwindcss/forms": "^0.5.7"
},
"lint-staged": {
"**/*.{cls,cmp,component,css,html,js,json,md,page,trigger,xml,yaml,yml}": [
"**/*.{cmp,component,css,html,js,json,md,page,trigger,xml,yaml,yml}": [
"prettier --write"
],
"**/{aura,lwc}/**/*.js": [
"**/{lwc}/**/*.js": [
"eslint"
]
}
Expand Down

0 comments on commit a10f96f

Please sign in to comment.