Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor(RSS-ECOMM-5_09): separate wishlist button into component #345

Merged
merged 2 commits into from
Jun 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
77 changes: 17 additions & 60 deletions src/entities/ProductCard/model/ProductCardModel.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,16 @@
import type { AddCartItem, Cart } from '@/shared/types/cart.ts';
import type { Product, ProductInfoParams, Variant } from '@/shared/types/product.ts';
import type { ShoppingList, ShoppingListProduct } from '@/shared/types/shopping-list.ts';

import RouterModel from '@/app/Router/model/RouterModel.ts';
import ProductPriceModel from '@/entities/ProductPrice/model/ProductPriceModel.ts';
import WishlistButtonModel from '@/features/WishlistButton/model/WishlistButtonModel.ts';
import getCartModel from '@/shared/API/cart/model/CartModel.ts';
import getShoppingListModel from '@/shared/API/shopping-list/model/ShoppingListModel.ts';
import modal from '@/shared/Modal/model/ModalModel.ts';
import getStore from '@/shared/Store/Store.ts';
import { LANGUAGE_CHOICE } from '@/shared/constants/common.ts';
import { PAGE_ID } from '@/shared/constants/pages.ts';
import { buildPathName } from '@/shared/utils/buildPathname.ts';
import {
productAddedToCartMessage,
productAddedToWishListMessage,
productRemovedFromWishListMessage,
} from '@/shared/utils/messageTemplates.ts';
import { productAddedToCartMessage } from '@/shared/utils/messageTemplates.ts';
import { showErrorMessage, showSuccessMessage } from '@/shared/utils/userMessage.ts';
import ProductInfoModel from '@/widgets/ProductInfo/model/ProductInfoModel.ts';

Expand All @@ -32,13 +27,16 @@ class ProductCardModel {

private view: ProductCardView;

constructor(params: Product, currentSize: null | string, shoppingList: ShoppingList, cart: Cart) {
private wishlistButton: WishlistButtonModel;

constructor(params: Product, currentSize: null | string, cart: Cart) {
this.params = params;
this.currentSize = currentSize;
this.currentSize = currentSize ?? this.params.variant[0].size;
this.currentVariant = this.params.variant.find(({ size }) => size === currentSize) ?? this.params.variant[0];
this.view = new ProductCardView(params, currentSize);
this.price = new ProductPriceModel(this.currentVariant);
this.init(shoppingList, cart);
this.wishlistButton = new WishlistButtonModel(this.params);
this.init(cart);
}

private addProductToCartHandler(): void {
Expand All @@ -51,34 +49,6 @@ class ProductCardModel {
.catch(showErrorMessage);
}

private addProductToWishListHandler(): void {
getShoppingListModel()
.addProduct(this.params.id)
.then(() => {
showSuccessMessage(
productAddedToWishListMessage(
this.params.name[Number(getStore().getState().currentLanguage === LANGUAGE_CHOICE.RU)].value,
),
);
this.view.switchStateWishListButton(true);
})
.catch(showErrorMessage);
}

private deleteProductToWishListHandler(productInWishList: ShoppingListProduct): void {
getShoppingListModel()
.deleteProduct(productInWishList)
.then(() => {
showSuccessMessage(
productRemovedFromWishListMessage(
this.params.name[Number(getStore().getState().currentLanguage === LANGUAGE_CHOICE.RU)].value,
),
);
this.view.switchStateWishListButton(false);
})
.catch(showErrorMessage);
}

private getProductMeta(): AddCartItem {
return {
name: this.params.name[Number(getStore().getState().currentLanguage === LANGUAGE_CHOICE.RU)].value,
Expand Down Expand Up @@ -107,33 +77,20 @@ class ProductCardModel {
}
}

private hasProductInWishList(shoppingList: ShoppingList): void {
const result = shoppingList.products.find((product) => product.productId === this.params.id);
this.view.switchStateWishListButton(Boolean(result));
}

private init(shoppingList: ShoppingList, cart: Cart): void {
this.setButtonHandlers();
this.hasProductInWishList(shoppingList);
private init(cart: Cart): void {
this.setAddToCartButtonHandler();
this.hasProductInCart(cart);
this.goDetailsPageHandler();
this.view.getBottomWrapper().append(this.price.getHTML());
this.setCardHandler();
this.view.getBottomWrapper().append(this.price.getHTML());
this.view.getButtonsWrapper().append(this.wishlistButton.getHTML().getHTML());
}

private setButtonHandlers(): void {
const addToCartButton = this.view.getAddToCartButton();
const switchToWishListButton = this.view.getSwitchToWishListButton();
addToCartButton.getHTML().addEventListener('click', () => this.addProductToCartHandler());
switchToWishListButton.getHTML().addEventListener('click', async () => {
const shoppingList = await getShoppingListModel().getShoppingList();
const productInWishList = shoppingList.products.find((product) => product.productId === this.params.id);
if (productInWishList) {
this.deleteProductToWishListHandler(productInWishList);
} else {
this.addProductToWishListHandler();
}
});
private setAddToCartButtonHandler(): void {
this.view
.getAddToCartButton()
.getHTML()
.addEventListener('click', () => this.addProductToCartHandler());
}

private setCardHandler(): void {
Expand Down
29 changes: 1 addition & 28 deletions src/entities/ProductCard/view/ProductCardView.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,13 +44,10 @@ class ProductCardView {

private productShortDescription: HTMLParagraphElement;

private switchToWishListButton: ButtonModel;

constructor(params: ProductCardParams, currentSize: null | string) {
this.params = params;
this.currentSize = currentSize;
this.addToCartButton = this.createAddToCartButton();
this.switchToWishListButton = this.createSwitchToWishListButton();
this.goDetailsPageLink = this.createGoDetailsPageLink();
this.buttonsWrapper = this.createButtonsWrapper();
this.productImage = this.createProductImage();
Expand Down Expand Up @@ -108,11 +105,7 @@ class ProductCardView {
tag: 'div',
});

this.buttonsWrapper.append(
this.addToCartButton.getHTML(),
this.switchToWishListButton.getHTML(),
this.goDetailsPageLink.getHTML(),
);
this.buttonsWrapper.append(this.addToCartButton.getHTML(), this.goDetailsPageLink.getHTML());

return this.buttonsWrapper;
}
Expand Down Expand Up @@ -249,18 +242,6 @@ class ProductCardView {
return this.productShortDescription;
}

private createSwitchToWishListButton(): ButtonModel {
this.switchToWishListButton = new ButtonModel({
classes: [styles.switchToWishListButton],
});

const svg = document.createElementNS(SVG_DETAILS.SVG_URL, 'svg');
svg.append(createSVGUse(SVG_DETAILS.FILL_HEART));
this.switchToWishListButton.getHTML().append(svg);

return this.switchToWishListButton;
}

private updateMoreButtonText(moreButton: HTMLButtonElement): void {
const { currentLanguage } = getStore().getState();
const moreText = MORE_TEXT[currentLanguage];
Expand Down Expand Up @@ -293,14 +274,6 @@ class ProductCardView {
public getMoreButton(): ButtonModel {
return this.moreButton;
}

public getSwitchToWishListButton(): ButtonModel {
return this.switchToWishListButton;
}

public switchStateWishListButton(hasProductInWishList: boolean): void {
this.switchToWishListButton.getHTML().classList.toggle(styles.inWishList, hasProductInWishList);
}
}

export default ProductCardView;
36 changes: 0 additions & 36 deletions src/entities/ProductCard/view/productCardView.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,6 @@
}

.addToCartButton,
.switchToWishListButton,
.goDetailsPageLink {
position: relative;
outline: calc(var(--one) * 1.5) solid var(--noble-gray-700);
Expand All @@ -90,10 +89,7 @@
&:active {
transform: scale(0.9);
}
}

.addToCartButton,
.goDetailsPageLink {
@media (hover: hover) {
&:hover {
outline: calc(var(--one) * 1.5) solid var(--steam-green-400);
Expand All @@ -112,38 +108,6 @@
}
}

.inWishList {
outline: calc(var(--one) * 1.5) solid var(--red-power-600);

svg {
fill: var(--red-power-600);
}
}

.switchToWishListButton {
@media (hover: hover) {
&:hover {
outline: calc(var(--one) * 1.5) solid var(--red-power-600);

svg {
fill: var(--red-power-600);
}
}
}

&.inWishList {
@media (hover: hover) {
&:hover {
outline: calc(var(--one) * 1.5) solid var(--noble-gray-700);

svg {
fill: var(--noble-gray-700);
}
}
}
}
}

.bottomWrapper {
display: flex;
flex-grow: 1;
Expand Down
23 changes: 10 additions & 13 deletions src/entities/PromocodeSlider/view/PromoCodeSliderView.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@ import getCustomerModel from '@/shared/API/customer/model/CustomerModel.ts';
import InputModel from '@/shared/Input/model/InputModel.ts';
import getStore from '@/shared/Store/Store.ts';
import observeStore, { selectCurrentLanguage } from '@/shared/Store/observer.ts';
import { AUTOCOMPLETE_OPTION } from '@/shared/constants/common.ts';
import { INPUT_TYPE } from '@/shared/constants/forms.ts';
import PROMO_SLIDER_CONTENT from '@/shared/constants/promo.ts';
import SVG_DETAILS from '@/shared/constants/svg.ts';
import calcUserBirthDayRange from '@/shared/utils/calcUserBirthDayRange.ts';
Expand Down Expand Up @@ -59,10 +57,15 @@ class PromoCodeSliderView {
});

observeStore(selectCurrentLanguage, () => {
start.innerHTML = PROMO_SLIDER_CONTENT[index][getStore().getState().currentLanguage].date.end
? `${PROMO_SLIDER_CONTENT[index][getStore().getState().currentLanguage].date.start} —`
: PROMO_SLIDER_CONTENT[index][getStore().getState().currentLanguage].date.start;
end.textContent = PROMO_SLIDER_CONTENT[index][getStore().getState().currentLanguage].date.end ?? '';
if (currentUser) {
start.innerHTML = getStore().getState().isUserLoggedIn
? `${calcUserBirthDayRange(currentUser.birthDate).start} —`
: PROMO_SLIDER_CONTENT[index][getStore().getState().currentLanguage].date.start;
end.textContent = getStore().getState().isUserLoggedIn ? calcUserBirthDayRange(currentUser.birthDate).end : '';
} else {
start.innerHTML = PROMO_SLIDER_CONTENT[index][getStore().getState().currentLanguage].date.start;
end.textContent = PROMO_SLIDER_CONTENT[index][getStore().getState().currentLanguage].date.end ?? '';
}
});

date.append(start, end);
Expand Down Expand Up @@ -94,13 +97,7 @@ class PromoCodeSliderView {
tag: 'span',
});

const currentPromoCode = new InputModel({
autocomplete: AUTOCOMPLETE_OPTION.ON,
id: '',
placeholder: '',
type: INPUT_TYPE.TEXT,
value: code,
});
const currentPromoCode = new InputModel({ value: code });

currentPromoCode.getHTML().classList.add(styles.currentPromoCode);

Expand Down
2 changes: 0 additions & 2 deletions src/features/ProductSearch/view/ProductSearchView.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import RouterModel from '@/app/Router/model/RouterModel.ts';
import InputModel from '@/shared/Input/model/InputModel.ts';
import getStore from '@/shared/Store/Store.ts';
import observeStore, { selectCurrentLanguage } from '@/shared/Store/observer.ts';
import { AUTOCOMPLETE_OPTION } from '@/shared/constants/common.ts';
import { INPUT_TYPE } from '@/shared/constants/forms.ts';
import { SEARCH_PARAMS_FIELD } from '@/shared/constants/product.ts';
import { TEXT } from '@/shared/constants/sorting.ts';
Expand Down Expand Up @@ -32,7 +31,6 @@ class ProductSearchView {

private createSearchField(): InputModel {
this.searchField = new InputModel({
autocomplete: AUTOCOMPLETE_OPTION.ON,
placeholder: TEXT[getStore().getState().currentLanguage].SEARCH,
type: INPUT_TYPE.SEARCH,
});
Expand Down
88 changes: 88 additions & 0 deletions src/features/WishlistButton/model/WishlistButtonModel.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
import type ButtonModel from '@/shared/Button/model/ButtonModel.ts';
import type { Product } from '@/shared/types/product.ts';
import type { ShoppingList, ShoppingListProduct } from '@/shared/types/shopping-list.ts';

import getShoppingListModel from '@/shared/API/shopping-list/model/ShoppingListModel.ts';
import getStore from '@/shared/Store/Store.ts';
import { LANGUAGE_CHOICE } from '@/shared/constants/common.ts';
import { productAddedToWishListMessage, productRemovedFromWishListMessage } from '@/shared/utils/messageTemplates.ts';
import { showErrorMessage, showSuccessMessage } from '@/shared/utils/userMessage.ts';

import WishlistButtonView from '../view/WishlistButtonView.ts';

class WishlistButtonModel {
private params: Product;

private view = new WishlistButtonView();

constructor(params: Product) {
this.params = params;
this.init();
}

private addProductToWishListHandler(): void {
getShoppingListModel()
.addProduct(this.params.id)
.then(() => {
showSuccessMessage(
productAddedToWishListMessage(
this.params.name[Number(getStore().getState().currentLanguage === LANGUAGE_CHOICE.RU)].value,
),
);
this.view.switchStateWishListButton(true);
})
.catch(showErrorMessage);
}

private deleteProductToWishListHandler(productInWishList: ShoppingListProduct): void {
getShoppingListModel()
.deleteProduct(productInWishList)
.then(() => {
showSuccessMessage(
productRemovedFromWishListMessage(
this.params.name[Number(getStore().getState().currentLanguage === LANGUAGE_CHOICE.RU)].value,
),
);
this.view.switchStateWishListButton(false);
})
.catch(showErrorMessage);
}

private hasProductInWishList(shoppingList: ShoppingList): void {
const result = shoppingList.products.find((product) => product.productId === this.params.id);
this.view.switchStateWishListButton(Boolean(result));
}

private init(): void {
getShoppingListModel()
.getShoppingList()
.then((shoppingList) => {
this.hasProductInWishList(shoppingList);
this.setButtonHandler();
})
.catch(showErrorMessage);
}

private setButtonHandler(): void {
const switchToWishListButton = this.view.getHTML();
switchToWishListButton.getHTML().addEventListener('click', async () => {
const shoppingList = await getShoppingListModel().getShoppingList();
const productInWishList = shoppingList.products.find((product) => product.productId === this.params.id);
if (productInWishList) {
this.deleteProductToWishListHandler(productInWishList);
} else {
this.addProductToWishListHandler();
}
});
}

public getHTML(): ButtonModel {
return this.view.getHTML();
}

public getView(): WishlistButtonView {
return this.view;
}
}

export default WishlistButtonModel;
Loading