diff --git a/src/entities/ProductCard/model/ProductCardModel.ts b/src/entities/ProductCard/model/ProductCardModel.ts index e82b18f5..2ba4158b 100644 --- a/src/entities/ProductCard/model/ProductCardModel.ts +++ b/src/entities/ProductCard/model/ProductCardModel.ts @@ -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'; @@ -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 { @@ -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, @@ -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 { diff --git a/src/entities/ProductCard/view/ProductCardView.ts b/src/entities/ProductCard/view/ProductCardView.ts index b600eca8..efdcd475 100644 --- a/src/entities/ProductCard/view/ProductCardView.ts +++ b/src/entities/ProductCard/view/ProductCardView.ts @@ -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(); @@ -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; } @@ -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]; @@ -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; diff --git a/src/entities/ProductCard/view/productCardView.module.scss b/src/entities/ProductCard/view/productCardView.module.scss index 08118b0f..5d3fee0a 100644 --- a/src/entities/ProductCard/view/productCardView.module.scss +++ b/src/entities/ProductCard/view/productCardView.module.scss @@ -68,7 +68,6 @@ } .addToCartButton, -.switchToWishListButton, .goDetailsPageLink { position: relative; outline: calc(var(--one) * 1.5) solid var(--noble-gray-700); @@ -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); @@ -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; diff --git a/src/entities/PromocodeSlider/view/PromoCodeSliderView.ts b/src/entities/PromocodeSlider/view/PromoCodeSliderView.ts index c79fe5d3..d7d0edd7 100644 --- a/src/entities/PromocodeSlider/view/PromoCodeSliderView.ts +++ b/src/entities/PromocodeSlider/view/PromoCodeSliderView.ts @@ -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'; @@ -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); @@ -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); diff --git a/src/features/ProductSearch/view/ProductSearchView.ts b/src/features/ProductSearch/view/ProductSearchView.ts index d6b2de53..5301d403 100644 --- a/src/features/ProductSearch/view/ProductSearchView.ts +++ b/src/features/ProductSearch/view/ProductSearchView.ts @@ -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'; @@ -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, }); diff --git a/src/features/WishlistButton/model/WishlistButtonModel.ts b/src/features/WishlistButton/model/WishlistButtonModel.ts new file mode 100644 index 00000000..a8839170 --- /dev/null +++ b/src/features/WishlistButton/model/WishlistButtonModel.ts @@ -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; diff --git a/src/features/WishlistButton/view/WishlistButtonView.ts b/src/features/WishlistButton/view/WishlistButtonView.ts new file mode 100644 index 00000000..084151e7 --- /dev/null +++ b/src/features/WishlistButton/view/WishlistButtonView.ts @@ -0,0 +1,35 @@ +import ButtonModel from '@/shared/Button/model/ButtonModel.ts'; +import SVG_DETAILS from '@/shared/constants/svg.ts'; +import createSVGUse from '@/shared/utils/createSVGUse.ts'; + +import styles from './wishlistButtonView.module.scss'; + +class WishlistButtonView { + private switchToWishListButton: ButtonModel; + + constructor() { + this.switchToWishListButton = this.createHTML(); + } + + private createHTML(): 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; + } + + public getHTML(): ButtonModel { + return this.switchToWishListButton; + } + + public switchStateWishListButton(hasProductInWishList: boolean): void { + this.switchToWishListButton.getHTML().classList.toggle(styles.inWishList, hasProductInWishList); + } +} + +export default WishlistButtonView; diff --git a/src/features/WishlistButton/view/wishlistButtonView.module.scss b/src/features/WishlistButton/view/wishlistButtonView.module.scss new file mode 100644 index 00000000..5769ba6a --- /dev/null +++ b/src/features/WishlistButton/view/wishlistButtonView.module.scss @@ -0,0 +1,52 @@ +.switchToWishListButton { + position: relative; + outline: calc(var(--one) * 1.5) solid var(--noble-gray-700); + border-radius: var(--medium-br); + padding: var(--tiny-offset); + width: var(--small-offset); + height: var(--small-offset); + background-color: var(--white-tr); + transition: outline 0.2s; + backdrop-filter: blur(10px); + + svg { + width: var(--extra-small-offset); + height: var(--extra-small-offset); + fill: var(--noble-gray-800); + transition: fill 0.2s; + } + + &:active { + transform: scale(0.9); + } + + @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); + } + } + } + } +} + +.inWishList { + outline: calc(var(--one) * 1.5) solid var(--red-power-600); + + svg { + fill: var(--red-power-600); + } +} diff --git a/src/pages/CartPage/view/CartPageView.ts b/src/pages/CartPage/view/CartPageView.ts index 61485a5e..0b263bd6 100644 --- a/src/pages/CartPage/view/CartPageView.ts +++ b/src/pages/CartPage/view/CartPageView.ts @@ -10,7 +10,6 @@ import LinkModel from '@/shared/Link/model/LinkModel.ts'; import modal from '@/shared/Modal/model/ModalModel.ts'; import getStore from '@/shared/Store/Store.ts'; import { USER_MESSAGE } from '@/shared/constants/confirmUserMessage.ts'; -import { INPUT_TYPE } from '@/shared/constants/forms.ts'; import { PAGE_ID } from '@/shared/constants/pages.ts'; import createBaseElement from '@/shared/utils/createBaseElement.ts'; @@ -197,10 +196,8 @@ class CartPageView { private createCouponHTML(): HTMLDivElement { const couponWrap = createBaseElement({ cssClasses: [styles.totalWrap], tag: 'div' }); const couponInput = new InputModel({ - autocomplete: 'off', id: 'coupon', placeholder: TITLE.INPUT_COUPON[this.language], - type: INPUT_TYPE.TEXT, }); couponInput.getHTML().classList.add(styles.couponInput); diff --git a/src/pages/CooperationPage/view/CooperationPageView.ts b/src/pages/CooperationPage/view/CooperationPageView.ts index 0f5731ef..18967c9c 100644 --- a/src/pages/CooperationPage/view/CooperationPageView.ts +++ b/src/pages/CooperationPage/view/CooperationPageView.ts @@ -70,7 +70,7 @@ class CooperationPageView { private createSubtitle(subtitle: string): HTMLHeadingElement { const subtitleElement = createBaseElement({ cssClasses: [styles.cooperationSubtitle], - tag: 'h2', + tag: 'h3', }); subtitleElement.textContent = subtitle; return subtitleElement; diff --git a/src/shared/Input/view/InputView.ts b/src/shared/Input/view/InputView.ts index d8a00c87..b8cbe671 100644 --- a/src/shared/Input/view/InputView.ts +++ b/src/shared/Input/view/InputView.ts @@ -1,5 +1,7 @@ import type { InputParams } from '@/shared/types/form'; +import { AUTOCOMPLETE_OPTION } from '@/shared/constants/common.ts'; +import { INPUT_TYPE } from '@/shared/constants/forms.ts'; import createBaseElement from '@/shared/utils/createBaseElement.ts'; class InputView { @@ -12,14 +14,14 @@ class InputView { private createHTML(attrs: InputParams): HTMLInputElement { this.input = createBaseElement({ attributes: { - autocomplete: attrs.autocomplete, + autocomplete: attrs.autocomplete ?? AUTOCOMPLETE_OPTION.ON, id: attrs.id || '', lang: attrs.lang || '', max: String(attrs.max || 0), min: String(attrs.min || 0), placeholder: attrs.placeholder || '', step: String(attrs.step || 1), - type: attrs.type, + type: attrs.type ?? INPUT_TYPE.TEXT, value: attrs.value || '', }, tag: 'input', diff --git a/src/shared/types/form.ts b/src/shared/types/form.ts index c5c721aa..dc196244 100644 --- a/src/shared/types/form.ts +++ b/src/shared/types/form.ts @@ -1,13 +1,13 @@ export interface InputParams { - autocomplete: 'off' | 'on'; + autocomplete?: 'off' | 'on'; data?: Record; id?: string; lang?: string; max?: null | number; min?: null | number; - placeholder: null | string; + placeholder?: null | string; step?: null | number; - type: 'checkbox' | 'color' | 'date' | 'email' | 'number' | 'password' | 'search' | 'tel' | 'text'; + type?: 'checkbox' | 'color' | 'date' | 'email' | 'number' | 'password' | 'search' | 'tel' | 'text'; value?: null | string; } diff --git a/src/widgets/Catalog/model/CatalogModel.ts b/src/widgets/Catalog/model/CatalogModel.ts index 18e2e441..c3fb03a8 100644 --- a/src/widgets/Catalog/model/CatalogModel.ts +++ b/src/widgets/Catalog/model/CatalogModel.ts @@ -12,7 +12,6 @@ import ProductSortsModel from '@/features/ProductSorts/model/ProductSortsModel.t import getCartModel from '@/shared/API/cart/model/CartModel.ts'; import getProductModel from '@/shared/API/product/model/ProductModel.ts'; import FilterProduct from '@/shared/API/product/utils/filter.ts'; -import getShoppingListModel from '@/shared/API/shopping-list/model/ShoppingListModel.ts'; import { FilterFields, SortDirection, SortFields } from '@/shared/API/types/type.ts'; import EventMediatorModel from '@/shared/EventMediator/model/EventMediatorModel.ts'; import LoaderModel from '@/shared/Loader/model/LoaderModel.ts'; @@ -99,10 +98,9 @@ class CatalogModel { const productsInfo = await this.getProductsInfo(options); this.pagination?.getHTML().remove(); if (productsInfo?.products?.length) { - const shoppingList = await getShoppingListModel().getShoppingList(); const cart = await getCartModel().getCart(); productsInfo.products.forEach((productData) => { - const product = new ProductCardModel(productData, this.currentSize, shoppingList, cart); + const product = new ProductCardModel(productData, this.currentSize, cart); productList.append(product.getHTML()); }); this.view.switchEmptyList(!productsInfo?.products?.length); diff --git a/src/widgets/Header/view/HeaderView.ts b/src/widgets/Header/view/HeaderView.ts index d440a9e5..f3bc749c 100644 --- a/src/widgets/Header/view/HeaderView.ts +++ b/src/widgets/Header/view/HeaderView.ts @@ -7,7 +7,7 @@ import getStore from '@/shared/Store/Store.ts'; import { switchAppTheme } from '@/shared/Store/actions.ts'; import observeStore, { selectCurrentPage, selectIsUserLoggedIn } from '@/shared/Store/observer.ts'; import { BUTTON_TEXT, BUTTON_TEXT_KEYS } from '@/shared/constants/buttons.ts'; -import { AUTOCOMPLETE_OPTION, LANGUAGE_CHOICE } from '@/shared/constants/common.ts'; +import { LANGUAGE_CHOICE } from '@/shared/constants/common.ts'; import { INPUT_TYPE } from '@/shared/constants/forms.ts'; import { PAGE_ID } from '@/shared/constants/pages.ts'; import APP_THEME from '@/shared/constants/styles.ts'; @@ -182,9 +182,7 @@ class HeaderView { private createSwitchLanguageCheckbox(): InputModel { this.switchLanguageCheckbox = new InputModel({ - autocomplete: AUTOCOMPLETE_OPTION.OFF, id: styles.switchLanguageLabel, - placeholder: '', type: INPUT_TYPE.CHECK_BOX, }); this.switchLanguageCheckbox.getHTML().classList.add(styles.switchLanguageCheckbox); @@ -214,9 +212,7 @@ class HeaderView { private createSwitchThemeCheckbox(): InputModel { this.switchThemeCheckbox = new InputModel({ - autocomplete: AUTOCOMPLETE_OPTION.OFF, id: styles.switchThemeLabel, - placeholder: '', type: INPUT_TYPE.CHECK_BOX, }); this.switchThemeCheckbox.getHTML().classList.add(styles.switchThemeCheckbox); diff --git a/src/widgets/ProductInfo/model/ProductInfoModel.ts b/src/widgets/ProductInfo/model/ProductInfoModel.ts index 033e1678..76a6dfb5 100644 --- a/src/widgets/ProductInfo/model/ProductInfoModel.ts +++ b/src/widgets/ProductInfo/model/ProductInfoModel.ts @@ -1,12 +1,11 @@ import type { Cart } from '@/shared/types/cart.ts'; import type { ProductInfoParams, Variant } from '@/shared/types/product.ts'; -import type { ShoppingListProduct } from '@/shared/types/shopping-list.ts'; import RouterModel from '@/app/Router/model/RouterModel.ts'; import ProductModalSliderModel from '@/entities/ProductModalSlider/model/ProductModalSliderModel.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 EventMediatorModel from '@/shared/EventMediator/model/EventMediatorModel.ts'; import LoaderModel from '@/shared/Loader/model/LoaderModel.ts'; import modal from '@/shared/Modal/model/ModalModel.ts'; @@ -16,12 +15,7 @@ import MEDIATOR_EVENT from '@/shared/constants/events.ts'; import { PAGE_ID } from '@/shared/constants/pages.ts'; import { LOADER_SIZE } from '@/shared/constants/sizes.ts'; import { buildPathName } from '@/shared/utils/buildPathname.ts'; -import { - productAddedToCartMessage, - productAddedToWishListMessage, - productRemovedFromCartMessage, - productRemovedFromWishListMessage, -} from '@/shared/utils/messageTemplates.ts'; +import { productAddedToCartMessage, productRemovedFromCartMessage } from '@/shared/utils/messageTemplates.ts'; import { showErrorMessage, showSuccessMessage } from '@/shared/utils/userMessage.ts'; import Swiper from 'swiper'; import 'swiper/css'; @@ -47,12 +41,15 @@ class ProductInfoModel { private view: ProductInfoView; + private wishlistButton: WishlistButtonModel; + constructor(params: ProductInfoParams) { this.params = params; this.view = new ProductInfoView(this.params); this.currentVariant = this.params.variant.find(({ size }) => size === this.params.currentSize) ?? this.params.variant[0]; this.price = new ProductPriceModel(this.currentVariant); + this.wishlistButton = new WishlistButtonModel(this.params); this.init(); } @@ -79,21 +76,6 @@ class ProductInfoModel { .finally(() => loader.remove()); } - 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); - EventMediatorModel.getInstance().notify(MEDIATOR_EVENT.REDRAW_PRODUCTS, ''); - }) - .catch(showErrorMessage); - } - private deleteProductFromCart(cart: Cart): void { const currentProduct = cart.products.find((product) => product.key === this.params.key); if (currentProduct) { @@ -115,21 +97,6 @@ class ProductInfoModel { } } - private deleteProductToWishListHandler(productInWishList: ShoppingListProduct): void { - getShoppingListModel() - .deleteProduct(productInWishList) - .then(() => { - showSuccessMessage( - productRemovedFromWishListMessage( - this.params.name[Number(getStore().getState().currentLanguage === LANGUAGE_CHOICE.RU)].value, - ), - ); - EventMediatorModel.getInstance().notify(MEDIATOR_EVENT.REDRAW_PRODUCTS, ''); - this.view.switchStateWishListButton(false); - }) - .catch(showErrorMessage); - } - private init(): void { this.smallSlider = new Swiper(this.view.getSmallSlider(), { direction: 'vertical', @@ -159,8 +126,8 @@ class ProductInfoModel { }); this.view.getRightWrapper().append(this.price.getHTML()); + this.view.getButtonsWrapper().append(this.wishlistButton.getHTML().getHTML()); this.switchToCartButtonHandler(); - this.switchToWishListButtonHandler(); this.setSizeButtonHandler(); } @@ -203,19 +170,6 @@ class ProductInfoModel { }); } - private switchToWishListButtonHandler(): void { - const switchToWishListButton = this.view.getSwitchToWishListButton(); - 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(): HTMLDivElement { return this.view.getHTML(); } diff --git a/src/widgets/ProductInfo/view/ProductInfoView.ts b/src/widgets/ProductInfo/view/ProductInfoView.ts index 3f034718..18dcb146 100644 --- a/src/widgets/ProductInfo/view/ProductInfoView.ts +++ b/src/widgets/ProductInfo/view/ProductInfoView.ts @@ -1,15 +1,13 @@ import type { ProductInfoParams } from '@/shared/types/product'; import getCartModel from '@/shared/API/cart/model/CartModel.ts'; -import getShoppingListModel from '@/shared/API/shopping-list/model/ShoppingListModel.ts'; import ButtonModel from '@/shared/Button/model/ButtonModel.ts'; import InputModel from '@/shared/Input/model/InputModel.ts'; import LoaderModel from '@/shared/Loader/model/LoaderModel.ts'; import getStore from '@/shared/Store/Store.ts'; import observeStore, { selectCurrentLanguage } from '@/shared/Store/observer.ts'; import { BUTTON_TEXT } from '@/shared/constants/buttons.ts'; -import { AUTOCOMPLETE_OPTION, LANGUAGE_CHOICE } from '@/shared/constants/common.ts'; -import { INPUT_TYPE } from '@/shared/constants/forms.ts'; +import { LANGUAGE_CHOICE } from '@/shared/constants/common.ts'; import { PRODUCT_INFO_TEXT, PRODUCT_INFO_TEXT_KEYS } from '@/shared/constants/product.ts'; import { LOADER_SIZE } from '@/shared/constants/sizes.ts'; import SVG_DETAILS from '@/shared/constants/svg.ts'; @@ -48,8 +46,6 @@ class ProductInfoView { private switchToCartButton: ButtonModel; - private switchToWishListButton: ButtonModel; - private title: HTMLHeadingElement; private view: HTMLDivElement; @@ -63,7 +59,6 @@ class ProductInfoView { this.SKUSpan = this.createSKUSpan(); this.categoriesSpan = this.createCategoriesSpan(); this.switchToCartButton = this.createSwitchToCartButton(); - this.switchToWishListButton = this.createSwitchToWishListButton(); this.buttonsWrapper = this.createButtonsWrapper(); this.rightWrapper = this.createRightWrapper(); this.view = this.createHTML(); @@ -128,7 +123,7 @@ class ProductInfoView { tag: 'div', }); - this.buttonsWrapper.append(this.switchToCartButton.getHTML(), this.switchToWishListButton.getHTML()); + this.buttonsWrapper.append(this.switchToCartButton.getHTML()); return this.buttonsWrapper; } @@ -268,13 +263,7 @@ class ProductInfoView { tag: 'span', }); - const currentSKU = new InputModel({ - autocomplete: AUTOCOMPLETE_OPTION.ON, - id: '', - placeholder: '', - type: INPUT_TYPE.TEXT, - value: this.params.key, - }); + const currentSKU = new InputModel({ value: this.params.key }); currentSKU.getHTML().classList.add('currentSKU'); @@ -415,20 +404,6 @@ class ProductInfoView { return this.switchToCartButton; } - private createSwitchToWishListButton(): ButtonModel { - this.switchToWishListButton = new ButtonModel({ - classes: ['switchToWishListButton'], - }); - - const svg = document.createElementNS(SVG_DETAILS.SVG_URL, 'svg'); - svg.append(createSVGUse(SVG_DETAILS.FILL_HEART)); - this.switchToWishListButton.getHTML().append(svg); - - this.hasProductInWishList(); - - return this.switchToWishListButton; - } - private hasProductInToCart(): void { getCartModel() .getCart() @@ -446,16 +421,6 @@ class ProductInfoView { .catch(showErrorMessage); } - private hasProductInWishList(): void { - getShoppingListModel() - .getShoppingList() - .then((shoppingList) => { - const result = shoppingList.products.find((product) => product.productId === this.params.id); - this.switchStateWishListButton(Boolean(result)); - }) - .catch(showErrorMessage); - } - public getBigSlider(): HTMLDivElement { return this.bigSlider; } @@ -464,6 +429,10 @@ class ProductInfoView { return this.bigSliderSlides; } + public getButtonsWrapper(): HTMLDivElement { + return this.buttonsWrapper; + } + public getHTML(): HTMLDivElement { return this.view; } @@ -484,14 +453,6 @@ class ProductInfoView { return this.switchToCartButton; } - public getSwitchToWishListButton(): ButtonModel { - return this.switchToWishListButton; - } - - public switchStateWishListButton(hasProductInWishList: boolean): void { - this.switchToWishListButton.getHTML().classList.toggle('inWishList', hasProductInWishList); - } - public switchToCartButtonText(hasCart: boolean): void { if (hasCart) { this.switchToCartButton.getHTML().textContent = BUTTON_TEXT[getStore().getState().currentLanguage].DELETE_PRODUCT; diff --git a/src/widgets/ProductInfo/view/productInfoView.scss b/src/widgets/ProductInfo/view/productInfoView.scss index d8af7842..bb890343 100644 --- a/src/widgets/ProductInfo/view/productInfoView.scss +++ b/src/widgets/ProductInfo/view/productInfoView.scss @@ -111,9 +111,9 @@ } .sizesWrapper { - display: grid; + display: flex; + align-items: center; order: 4; - grid-template-columns: max-content; width: max-content; font: var(--regular-font); letter-spacing: var(--one); @@ -132,8 +132,6 @@ display: flex; align-items: center; justify-content: center; - justify-self: center; - grid-row: 2; border: var(--one) solid var(--noble-gray-800); border-radius: 50%; width: 2rem; @@ -235,60 +233,6 @@ } } -.switchToWishListButton { - outline: calc(var(--one) * 1.5) solid var(--noble-gray-700); - border-radius: var(--medium-br); - padding: var(--tiny-offset); - width: var(--small-offset); - height: var(--small-offset); - background-color: var(--white-tr); - transition: - transform 0.2s, - outline 0.2s; - backdrop-filter: blur(10px); - - svg { - width: var(--extra-small-offset); - height: var(--extra-small-offset); - fill: var(--noble-gray-800); - transition: fill 0.2s; - } - - &:active { - transform: scale(0.9); - } - - @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); - } - } - } - } -} - -.inWishList { - outline: calc(var(--one) * 1.5) solid var(--red-power-600); - - svg { - fill: var(--red-power-600); - } -} - .modalProductInfoWrapper { .wrapper { margin-bottom: 0;