Skip to content

Commit

Permalink
Cart removal buttons in saved cart menu (#8)
Browse files Browse the repository at this point in the history
* cart remove buttons in cart view (closes #7)
* make index more abstract
* inc version, update dependencies
  • Loading branch information
darksworm authored Mar 20, 2021
1 parent 79e417e commit effaf0a
Show file tree
Hide file tree
Showing 22 changed files with 2,738 additions and 1,602 deletions.
3,050 changes: 1,796 additions & 1,254 deletions package-lock.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "rimi-smart-baskets",
"version": "0.5.2",
"version": "0.6.0",
"description": "build your cart from presets in the rimi e-store",
"main": "src/index.js",
"scripts": {
Expand Down
59 changes: 10 additions & 49 deletions src/index.js
Original file line number Diff line number Diff line change
@@ -1,61 +1,22 @@
import CSSInjector from "./lib/generic/cssInjector"

import Rimi from "./lib/rimi/rimi";
import CartStorage from "./lib/cart/cartStorage";

import SaveCartButtonCreator from "./lib/ui/saveCartButtonCreator";
import AppendCartButtonCreator from "./lib/ui/appendCartButtonCreator";
import CartAbandonmentConfirmer from "./lib/ui/cartAbandonmentConfirmer";
import CartUpdateValidator from "./lib/cart/cartUpdateValidator";

import ProductListHTMLBuilder from "./lib/ui/productListHTMLBuilder";
import CartUpdateProgressIndicator from "./lib/ui/cartUpdateProgressIndicator";

import NotificationService from "./lib/ui/notificationService";
import PromptService from "./lib/ui/promptService";

import notyfCSS from 'notyf/notyf.min.css'
import smartBasketCSS from './static/style.css'
import cartSVG from './static/cart.svg'
import productAdditionWarningFooter from './static/product-addition-warning-footer.html';
import {createCartManipulationButtons} from "./lib/feature/createCartManipulationButtons";
import {notifyUserIfCartUpdateFailed} from "./lib/feature/notifyUserIfCartUpdateFailed";
import {promptUserWhenAboutToAbandonCart} from "./lib/feature/promptUserWhenAboutToAbandonCart";
import {injectCustomStyles} from "./lib/feature/injectCustomStyles";

(function () {
"use strict";

const rimi = new Rimi(window, axios);

if (false === rimi.dom.isLoggedIn()) {
return rimi.dom.redirectToLoginPage();
}

const cartStorage = new CartStorage(localStorage);
const promptService = new PromptService(Swal, new Notyf());

const notificationService = new NotificationService(new Notyf());
const promptService = new PromptService(Swal);

let externalStylesheets = [smartBasketCSS, notyfCSS];
new CSSInjector(document).injectMultiple(externalStylesheets);

if (rimi.dom.isInSavedCart()) {
const creator = new SaveCartButtonCreator(document, cartStorage, rimi.dom);
creator.setNotificationHandler(notificationService);
creator.createButton();
} else {
const creator = new AppendCartButtonCreator(document, cartStorage, rimi);
const progressIndicator = new CartUpdateProgressIndicator(document, rimi.refresh.bind(rimi));
creator.setProgressHandler(progressIndicator);
creator.createButtons(cartSVG);
}

const confirmer = new CartAbandonmentConfirmer(document, rimi.dom, promptService);
confirmer.bindToCartChangeButtons();
rimi.dom.forceUserLogin();

let cartUpdate = cartStorage.popCartUpdate();
if (cartUpdate) {
let validator = new CartUpdateValidator(rimi.dom.getCurrentCart().products, cartUpdate);
if (validator.hasProductUpdateFailed()) {
let listBuilder = new ProductListHTMLBuilder(validator.getFailedProducts());
promptService.notifyProductAdditionFailed(listBuilder.build(), productAdditionWarningFooter);
}
}
injectCustomStyles(document);
createCartManipulationButtons(document, rimi, cartStorage, promptService);
promptUserWhenAboutToAbandonCart(document, rimi.dom, promptService);
notifyUserIfCartUpdateFailed(rimi.dom, cartStorage, promptService);
})();
50 changes: 50 additions & 0 deletions src/lib/cart/cartRemover.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
export default class CartRemover {
constructor(document, rimiAPI, promptService) {
this.document = document;
this.rimiAPI = rimiAPI;
this.promptService = promptService;
}

promptAndRemoveCart(name, id) {
this._findCartLiElement(id);

this.promptService.promptCartRemoval(name)
.then(() => this._stopMenuFromClosing())
.then(() => this._removeSavedCart(name, id))
.catch(() => this._stopMenuFromClosing());
}

_removeSavedCart(name, id) {
return this.rimiAPI.removeSavedCart(id)
.then(() => this._removeCartListing(id))
.then(() => this._notifySuccess(name))
.catch(() => this._notifyError());
}

_notifySuccess(cartName) {
this.promptService.notifySuccess(`Cart ${cartName} removed!`, 2000);
}

_notifyError() {
this.promptService.notifyError(`Cart removal failed!`, 2000);
}

_findCartLiElement(cartId) {
const btn = this.document.querySelector(`.saved-cart-popup.js-saved li button[value='${cartId}']`);

if (btn) {
return btn.parentElement;
} else {
throw new Error(`Cart with id ${cartId} does not exist!`);
}
}

_stopMenuFromClosing() {
let elem = this.document.querySelector('section.cart');
elem.classList.add('-saved-cart-active');
}

_removeCartListing(cartId) {
this._findCartLiElement(cartId).remove();
}
}
40 changes: 40 additions & 0 deletions src/lib/cart/removeCartButtonCreator.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
export default class RemoveCartButtonCreator {
constructor(document) {
this.document = document;
}

createButtons(innerHTML, onClick) {
this.getCartButtonElements()
.forEach((elem) => {
let button = this.createRemoveBtn(innerHTML, elem, onClick);
elem.prepend(button);
});
}

getCartButtonElements() {
return this.document.querySelectorAll(".saved-cart-popup.js-saved li:not(:last-child) button[name='cart']");
}

createRemoveBtn(innerHTML, cartButtonElement, onClick) {
let removeBtn = this.document.createElement("span");
const attrs = this._getRemoveBtnAttrs(cartButtonElement);

removeBtn.classList.add("smart-basket-remove");
removeBtn.innerHTML = innerHTML;

removeBtn.addEventListener('click', (event) => {
event.stopPropagation();
event.preventDefault();
onClick(attrs.cartTitle, attrs.cartId);
});

return removeBtn;
}

_getRemoveBtnAttrs(cartButtonElement) {
return {
cartTitle: cartButtonElement.textContent.trim(),
cartId: cartButtonElement.value
}
}
}
43 changes: 43 additions & 0 deletions src/lib/feature/createCartManipulationButtons.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import SaveCartButtonCreator from "../ui/saveCartButtonCreator";
import AppendCartButtonCreator from "../ui/appendCartButtonCreator";
import CartUpdateProgressIndicator from "../ui/cartUpdateProgressIndicator";
import RemoveCartButtonCreator from "../cart/removeCartButtonCreator";
import CartRemover from "../cart/cartRemover";

import cartSVG from '../../static/cart.svg';
import removeSVG from '../../static/remove.svg';

export function createCartManipulationButtons(document, rimi, cartStorage, promptService) {
if (rimi.dom.isInSavedCart()) {
createSaveCartInSmartCartsButton(document, cartStorage, rimi.dom, promptService);
} else {
createAppendCartButtons(document, cartStorage, rimi);
}

createSavedCartRemoveButtons(document, rimi.api, promptService);
}

function createSaveCartInSmartCartsButton(document, cartStorage, rimiDOM, promptService) {
const creator = new SaveCartButtonCreator(document, cartStorage, rimiDOM);

creator.setNotificationHandler(promptService);
creator.createButton();
}

function createAppendCartButtons(document, cartStorage, rimi) {
const creator = new AppendCartButtonCreator(document, cartStorage, rimi);
const progressIndicator = new CartUpdateProgressIndicator(document, rimi.refresh.bind(rimi));

creator.setProgressHandler(progressIndicator);
creator.createButtons(cartSVG);
}

function createSavedCartRemoveButtons (document, rimiAPI, promptService) {
const removeBtnCreator = new RemoveCartButtonCreator(document);
const cartRemover = new CartRemover(document, rimiAPI, promptService);

removeBtnCreator.createButtons(
removeSVG,
cartRemover.promptAndRemoveCart.bind(cartRemover)
);
}
9 changes: 9 additions & 0 deletions src/lib/feature/injectCustomStyles.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import CSSInjector from "../generic/cssInjector";

import notyfCSS from 'notyf/notyf.min.css';
import smartBasketCSS from '../../static/style.css';

export function injectCustomStyles(document) {
const externalStylesheets = [smartBasketCSS, notyfCSS];
new CSSInjector(document).injectMultiple(externalStylesheets);
}
18 changes: 18 additions & 0 deletions src/lib/feature/notifyUserIfCartUpdateFailed.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import CartUpdateValidator from "../cart/cartUpdateValidator";
import ProductListHTMLBuilder from "../ui/productListHTMLBuilder";

import productAdditionWarningFooter from '../../static/product-addition-warning-footer.html';

export function notifyUserIfCartUpdateFailed(rimiDOM, cartStorage, promptService) {
const cartUpdate = cartStorage.popCartUpdate();

if (cartUpdate) {
const currentProducts = rimiDOM.getCurrentCart().products;
const validator = new CartUpdateValidator(currentProducts, cartUpdate);

if (validator.hasProductUpdateFailed()) {
const listBuilder = new ProductListHTMLBuilder(validator.getFailedProducts());
promptService.notifyProductAdditionFailed(listBuilder.build(), productAdditionWarningFooter);
}
}
}
6 changes: 6 additions & 0 deletions src/lib/feature/promptUserWhenAboutToAbandonCart.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import CartAbandonmentConfirmer from "../ui/cartAbandonmentConfirmer";

export function promptUserWhenAboutToAbandonCart(document, rimiDOM, promptService) {
const confirmer = new CartAbandonmentConfirmer(document, rimiDOM, promptService);
confirmer.bindToCartChangeButtons();
}
20 changes: 20 additions & 0 deletions src/lib/rimi/rimiAPI.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,26 @@ export default class RimiAPI {
};
}

removeSavedCart(cartId) {
return this.axios.post(
this._getRemoveSavedCartURL(),
this._getRemoveSavedCartPostData(cartId),
this._getAxiosConfig()
);
}

_getRemoveSavedCartURL() {
return "https://www.rimi.lv/e-veikals/lv/mans-konts/saglabatie-grozi/delete";
}

_getRemoveSavedCartPostData(cartId) {
return {
"code": cartId,
"_method": "delete",
"_token": this.token
};
}

_getAxiosConfig() {
return {
headers: {
Expand Down
10 changes: 8 additions & 2 deletions src/lib/rimi/rimiDOM.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,14 +62,14 @@ export default class RimiDOM {
return buttons.map(button => {
return {
id: button.value,
name: button.innerHTML
name: button.textContent.trim()
}
})
}

_getCartButtons() {
return this.window.document.querySelectorAll(
".saved-cart-popup > li > button:not(.js-new-cart)"
".saved-cart-popup > li > button[name='cart']:not(.js-new-cart)"
);
}

Expand Down Expand Up @@ -99,4 +99,10 @@ export default class RimiDOM {
redirectToLoginPage() {
this.window.location.href = '/e-veikals/account/login';
}

forceUserLogin() {
if (false === this.isLoggedIn()) {
return this.redirectToLoginPage();
}
}
}
17 changes: 0 additions & 17 deletions src/lib/ui/notificationService.js

This file was deleted.

Loading

0 comments on commit effaf0a

Please sign in to comment.