PageSourceSearch

https://www.officenational.co.za/scss/themes/officeNational/scripts/custom/Cart.js?v=26100801

js officenational.co.za collected 2026-10-08 01:58:21 UTC 11,494 bytes, 395 lines download raw bytes

1var CustomCart = (function ($) {
2
3	var _state = {
4		removeItemId: null
5	};
6
7	var _defaults = {
8		templates: {
9			custom: [],
10			summary:
11			{
12				ref: "summary",
13				template: "#CartSummaryTemplate",
14				target: _SF('cartSummary')
15			},
16			cartProduct:
17			{
18				ref: "cartProduct",
19				template: "#cartProductTemplate",
20				target: _SF('cartItemList')
21			},
22			cartGiftCard:
23			{
24				ref: "cartGiftCard",
25				template: "#cartGiftCardTemplate",
26				target: _SF('cartItemList')
27			},
28			cartHamper:
29			{
30				ref: "cartHamper",
31				template: "#cartHamperTemplate",
32				target: _SF('cartItemList')
33			},
34			cartConfiguration:
35			{
36				ref: "cartConfiguration",
37				template: "#cartConfigurationTemplate",
38				target: _SF('cartItemList')
39			},
40			cartBatch:
41			{
42				ref: "cartBatch",
43				template: "#cartBatchTemplate",
44				target: _SF('cartItemList')
45			},
46			cartBranding:
47			{
48				ref: "cartBranding",
49				template: "#cartBrandingTemplate",
50				target: _SF('cartItemList')
51			},
52			removeItem: {
53				ref: "removeItem",
54				template: "#removeItemTemplate",
55				target: _SF('removeItem')
56			},
57			mobile: {
58				mobileProduct:
59				{
60					ref: "mobileProduct",
61					template: "#cartProductMobileTemplate",
62					target: _SF('fauxTable')
63				},
64				mobileGiftCard:
65				{
66					ref: "mobileGiftCard",
67					template: "#cartGiftCardMobileTemplate",
68					target: _SF('fauxTable')
69				},
70				mobileHamper:
71				{
72					ref: "mobileHamper",
73					template: "#cartHamperMobileTemplate",
74					target: _SF('fauxTable')
75				},
76				mobileConfiguration:
77				{
78					ref: "mobileConfiguration",
79					template: "#cartConfigurationMobileTemplate",
80					target: _SF('fauxTable')
81				},
82				mobileBatch:
83				{
84					ref: "mobileBatch",
85					template: "#cartBatchMobileTemplate",
86					target: _SF('fauxTable')
87				},
88				mobileBranding:
89				{
90					ref: "mobileBranding",
91					template: "#cartBrandingMobileTemplate",
92					target: _SF('fauxTable')
93				},
94			}
95		},
96		_events: {
97			onBeforeLoad: null,
98			onAfterLoad: null
99		}
100	}
101
102	var _ready = () => {
103		// Render Custom Templates
104		_SFJS.render.templates(_defaults.templates.custom, _state);
105		// Prep _plugins 
106		$('[data-toggle="tooltip"]').tooltip();
107		// Do ready callback
108		_SFJS.utils.handleCallback(_defaults._events.onAfterLoad, _state);
109		// Remove placeholders
110		_SFJS.utils.removePlaceholders();
111	}
112
113	var _render = () => {
114		// Get data via SDK
115		sdk.cart.get({
116			requires: [
117				{
118					endpoint: sdk.store.getInfo,
119					ref: "Store"
120				},
121				{
122					endpoint: sdk.cart.validate,
123					ref: "Validation"
124				}
125			],
126			success: function (response) {
127				$.extend(SFUI, { store: response.requirements.Store }); // register in SFUI library  
128				$.extend(true, _state, { cart: response.data }, { cart: response.requirements }); // push data to local _state 				
129
130				_state.cart.TotalText = _SFJS.currency.parse(_state.cart.Total);
131
132				if (!_state.cart.Validation.Valid) {
133					$.each(_state.cart.Validation.Issues, function (idx, issue) {
134						$.each(issue.LineIds, function (idx, id) {
135							var item = _state.cart.Items.find(item => item.ItemId === id);
136							if (item) {
137								item['HasErrors'] = true;
138								item['Issues'] = issue;
139							}
140						});
141					});
142				}
143
144				$.each(_state.cart.Items, (i, item) => {
145					item['Picture'] = item.Pictures[0];
146					item['PriceText'] = _SFJS.currency.parse(item.Price);
147					item['SubTotalText'] = _SFJS.currency.parse(item.SubTotal);
148
149					_functions.parseChildCurrencyValues(item);
150
151					if (item.Children) {
152						item['HasViewMore'] = item.Children.length > 2 ? true : false;
153					}
154					if (item.ItemType === 'Hamper') {
155						_SFJS.render.template(_defaults.templates.cartHamper, item);
156						_SFJS.render.template(_defaults.templates.mobile.mobileHamper, item);
157					} else if (item.ItemType === 'GiftCard') {
158						_SFJS.render.template(_defaults.templates.cartGiftCard, item);
159						_SFJS.render.template(_defaults.templates.mobile.mobileGiftCard, item);
160					} else if (item.ItemType === 'Configuration') {
161						_SFJS.render.template(_defaults.templates.cartConfiguration, item);
162						_SFJS.render.template(_defaults.templates.mobile.mobileConfiguration, item);
163					} else if (item.ItemType === 'Batch') {
164						_SFJS.render.template(_defaults.templates.cartBatch, item);
165						_SFJS.render.template(_defaults.templates.mobile.mobileBatch, item);
166					} else if (item.ItemType === 'Branding') {
167						item['CartId'] = _state.cart.CartId;
168						_SFJS.render.template(_defaults.templates.cartBranding, item);
169						_SFJS.render.template(_defaults.templates.mobile.mobileBranding, item);
170					} else {
171						_SFJS.render.template(_defaults.templates.cartProduct, item);
172						_SFJS.render.template(_defaults.templates.mobile.mobileProduct, item);
173					}
174				});
175
176				_functions.reloadSummary();
177				_SFJS.render.template(_defaults.templates.removeItem, _state.cart);
178				_ready();
179			}
180		});
181	}
182
183	var _functions = {
184		init: function (props) {
185			// update _defaults with potential custom values from view
186			$.extend(true, _defaults, props);
187			// Do init callback
188			_SFJS.utils.handleCallback(_defaults._events.onBeforeLoad, _state);
189			// Render View
190			_render();
191
192			//Custom trigger GA4 event due to timing issue.
193			setTimeout(() => {
194				if (window.SFGA) {
195					console.log("view_cart");
196					SFGA.Event('view_cart', null, '/ajax/google-analytics-4/cart')
197				}
198			}, 2000);
199		},
200
201		parseChildCurrencyValues: function (item) {
202			// recursively parses child currency values
203			if (item?.Children && item?.Children.length) {
204				$.each(item.Children, function (idx, child) {
205					child['PriceText'] = _SFJS.currency.parse(child.Price);
206					child['SubTotalText'] = _SFJS.currency.parse(child.SubTotal);
207					child['TotalText'] = _SFJS.currency.parse(child.Total);
208
209					_functions.parseChildCurrencyValues(child)
210				});
211			} else {
212				return false;
213			}
214		},
215
216		updateCartItemValues: function (data) {
217			sdk.cart.updateItemQty({
218				success: function (response) {
219					var data = response.data;
220					data.TotalText = _SFJS.currency.parse(data.Total);
221					// update line items with new values, it's easier to just do them all instead of just the one that was updated
222					$.each(data.Items, (i, item) => {
223						item.SubTotalText = _SFJS.currency.parse(item.SubTotal);
224						$('[sfTarget="cartItem"][data-id="' + item.ItemId + '"]').find('[sfTarget-itemTotal]').html(item.SubTotalText);
225					});
226					_functions.reloadSummary();
227				},
228				data: data
229			});
230		},
231
232		increment: function (id) {
233			var input = $('[sfTarget-updateQty="' + id + '"]').find('input');
234			input.val(parseInt(input.val()) + 1);
235			var data = {
236				"Id": id,
237				"Qty": input.val()
238			}
239			_functions.updateCartItemValues(data);
240		},
241
242		decrement: function (id) {
243			var input = $('[sfTarget-updateQty="' + id + '"]').find('input');
244			input.val(parseInt(input.val()) - 1);
245			var qty = input.val();
246
247			if (parseInt(qty) <= 0) {
248				_functions.removeItem(id);
249				return;
250			}
251
252			var data = {
253				"Id": id,
254				"Qty": qty
255			}
256			_functions.updateCartItemValues(data);
257		},
258
259		updateQty: function (id) {
260			var qty = $('[name="qty"][data-itemid="' + id + '"]').val();
261
262			if (parseInt(qty) <= 0) {
263				_functions.removeItem(id);
264				return;
265			}
266
267			var data = {
268				"Id": id,
269				"Qty": qty
270			}
271			_functions.updateCartItemValues(data);
272		},
273
274		removeItem: function (id) {
275			_SF('removeItemModal').modal('show');
276			_state.removeItemId = id;
277		},
278
279		cancelRemoveItem: function () {
280
281			var item = $('[name="qty"][data-itemid="' + _state.removeItemId + '"]:visible');
282
283			//No need to update cart as you cancelled the remove
284			if (item.val() <= 0) item.val(1);
285
286			_state.removeItemId = null;
287			$('[sf-target-removeitemmodal]').modal('hide');
288		},
289
290		confirmRemoveItem: function () {
291			if (window.SFGA) SFGA.Event('remove_from_cart', null, '/ajax/google-analytics-4/cart/item?itemId=' + _state.removeItemId);
292			sdk.cart.removeItem({
293				success: function (response) {
294					$('[sfTarget="cartItem"][data-id="' + _state.removeItemId + '"]').remove();
295					$('[sfTarget="itemError"][data-id="' + _state.removeItemId + '"]').remove();
296					$('[sfTarget="viewMore"][data-id="' + _state.removeItemId + '"]').remove();
297					_functions.reloadSummary();
298					_state.removeItemId = null;
299				},
300				itemId: _state.removeItemId,
301			});
302			_SF('removeItemModal').modal('hide');
303		},
304
305		addPromocode: function () {
306			if (_SF('promocodeValue').val()) {
307				sdk.cart.addPromocode({
308					data: { Code: _SF('promocodeValue').val() },
309					success: function (response) {
310						var data = response.data;
311						if (data.Success) {
312							_functions.reloadSummary();
313							_SF('promocodeAction').attr('data-type', 'remove');
314							_SF('promocodeValue').attr('disabled', true);
315						} else {
316							Utils.Notify({
317								style: "error",
318								message: response.data.Warnings[0]
319							});
320							_SF('promocodeValue').val('');
321						}
322					}
323				});
324
325			}
326		},
327
328		removePromocode: function () {
329			var code = _SF('promocodeValue').val()
330			var encodedCode = encodeURIComponent(code);
331			sdk.cart.removePromocode({
332				code: encodedCode,
333				success: function (response) {
334					if (response.data.Success) {
335						_functions.reloadSummary();
336					} else {
337						Utils.Notify({
338							style: "error",
339							message: 'Unable to remove promocode "' + _SF('promocodeValue').val() + '"'
340						});
341					}
342				}
343			});
344			_SF('promocodeValue').val('');
345			_SF('promocodeAction').attr('data-type', 'apply');
346			_SF('promocodeValue').removeAttr('disabled');
347		},
348
349		reloadSummary: function () {
350			sdk.cart.get({
351				success: function (response) {
352					var data = response.data;
353					console.log(!data);
354					$.extend(true, _state, { cart: data }); // push data to local state
355					if (!data || data.ItemCount === 0) {
356						_SF('cartItems').addClass('hide');
357						_SF('noItemsInCart').removeClass('hide');
358					} else {
359						data.SubTotalText = _SFJS.currency.parse(data.SubTotal);
360						data.DiscountText = _SFJS.currency.parse(data.Discount);
361						data.ShippingText = _SFJS.currency.parse(data.Shipping);
362						data.GiftCardPaymentText = _SFJS.currency.parse(data.GiftCardPayment);
363						data.WalletPaymentText = _SFJS.currency.parse(data.WalletPayment);
364						data.TaxText = _SFJS.currency.parse(data.Tax);
365						data.TotalText = _SFJS.currency.parse(data.Total);
366						data.TotalDueText = _SFJS.currency.parse(data.TotalDue);
367
368
369						_SFJS.render.template(_defaults.templates.summary, data, true);
370					}
371				},
372			});
373		},
374
375		revealMore: function (itemId) {
376			var viewMore = $('[sfTarget="viewMore"][data-id="' + itemId + '"]');
377			if (viewMore.hasClass('full')) {
378				viewMore.removeClass('full');
379				$('[sftarget="cartItem"][data-id="' + itemId + '"] .wrap').removeClass('full');
380			} else {
381				viewMore.addClass('full');
382				$('[sftarget="cartItem"][data-id="' + itemId + '"] .wrap').addClass('full');
383			}
384		},
385
386		reject: function (event) {
387			console.log(event);
388			return event.charCode >= 48 && event.charCode <= 57;
389		}
390	}
391
392	return _functions;
393})(jQuery);
394
395$.extend(SFUI, { CustomCart }); // register in SFUI library

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.