From 761fecf67f5bf5127a08aa304f22cfa77928f8d7 Mon Sep 17 00:00:00 2001 From: Alexandr SaVBaD Waltz Date: Sun, 6 Jul 2025 19:49:26 +0300 Subject: [PATCH] Features: 1) Add `useWishlistOverwrite` composable for wishlist mutations, including adding, removing, and bulk actions; 2) Introduce new localized UI texts for cart and wishlist operations; 3) Enhance filtering logic with `parseAttributesString` and route query synchronization; Fixes: 1) Replace `ElNotification` calls with `useNotification` utility across all authentication and user-related composables; 2) Add missing semicolons in multiple index exports and styled components; 3) Resolve issues with reactivity in `useStore` composable by renaming and restructuring product variables; Extra: 1) Refactor localized strings and translations for better readability and maintenance; 2) Tweak styles including scoped styles, z-index adjustments, and SCSS mixins; 3) Remove unused components and imports to streamline storefront layout. --- storefront/app.vue | 11 +- storefront/assets/styles/main.scss | 6 +- .../assets/styles/modules/normalize.scss | 4 + storefront/assets/styles/ui/collapse.scss | 2 +- storefront/assets/styles/ui/notification.scss | 39 ++ storefront/assets/styles/ui/rating.scss | 17 + storefront/components/base/header/catalog.vue | 3 +- storefront/components/base/header/index.vue | 54 +- storefront/components/base/header/search.vue | 38 +- storefront/components/cards/product.vue | 89 ++- storefront/components/profile/navigation.vue | 79 +++ storefront/components/store/filter.vue | 42 +- storefront/components/store/index.vue | 20 +- storefront/components/store/top.vue | 8 +- storefront/components/ui/breadcrumbs.vue | 1 + storefront/components/ui/checkbox.vue | 13 +- storefront/components/ui/counter.vue | 27 - storefront/components/ui/input.vue | 72 +-- storefront/components/ui/textarea.vue | 42 +- storefront/composables/auth/index.ts | 12 +- storefront/composables/auth/useLogin.ts | 16 +- storefront/composables/auth/useNewPassword.ts | 19 +- .../composables/auth/usePasswordReset.ts | 19 +- storefront/composables/auth/useRefresh.ts | 11 +- storefront/composables/auth/useRegister.ts | 58 +- storefront/composables/brands/index.ts | 4 +- storefront/composables/breadcrumbs/index.ts | 2 +- storefront/composables/categories/index.ts | 6 +- storefront/composables/company/index.ts | 2 +- storefront/composables/config/index.ts | 2 +- storefront/composables/contact/index.ts | 2 +- .../composables/contact/useContactUs.ts | 19 +- storefront/composables/languages/index.ts | 6 +- storefront/composables/notification/index.ts | 1 + .../notification/useNotification.ts | 26 + storefront/composables/orders/index.ts | 2 +- .../composables/orders/useOrderOverwrite.ts | 176 ++++++ storefront/composables/products/index.ts | 6 +- .../composables/products/useProductBySlug.ts | 18 +- storefront/composables/rules/index.ts | 2 +- storefront/composables/scrollTo/index.ts | 1 + .../composables/scrollTo/useScrollTo.ts | 33 ++ storefront/composables/search/index.ts | 6 +- storefront/composables/search/useSearch.ts | 11 +- storefront/composables/store/index.ts | 4 +- storefront/composables/store/useFilters.ts | 26 +- storefront/composables/store/useStore.ts | 21 +- storefront/composables/user/index.ts | 2 +- .../composables/user/useUserActivation.ts | 19 +- storefront/composables/utils/index.ts | 4 +- storefront/composables/wishlist/index.ts | 3 +- .../wishlist/useWishlistOverwrite.ts | 152 +++++ .../graphql/fragments/products.fragment.ts | 8 + storefront/graphql/fragments/user.fragment.ts | 1 + storefront/graphql/mutations/cart.ts | 33 +- storefront/graphql/mutations/languages.ts | 3 + storefront/graphql/mutations/wishlist.ts | 29 +- .../graphql/queries/standalone/brands.ts | 2 +- .../graphql/queries/standalone/products.ts | 10 +- storefront/i18n/locales/en-gb.json | 51 +- storefront/nuxt.config.ts | 2 +- storefront/package-lock.json | 357 +++++++++++- storefront/pages/brand/[uuid].vue | 4 + storefront/pages/index.vue | 16 +- storefront/pages/product/[slug].vue | 521 +++++++++++++++++- storefront/pages/profile.vue | 46 ++ storefront/pages/profile/cart.vue | 87 +++ storefront/pages/profile/orders.vue | 15 + storefront/pages/profile/settings.vue | 15 + storefront/pages/profile/wishlist.vue | 175 ++++++ storefront/stores/cart.ts | 13 + storefront/types/api/orders.ts | 30 + storefront/types/api/wishlist.ts | 24 + storefront/types/app/products.ts | 10 +- storefront/types/app/user.ts | 1 + 75 files changed, 2336 insertions(+), 375 deletions(-) create mode 100644 storefront/assets/styles/ui/notification.scss create mode 100644 storefront/assets/styles/ui/rating.scss create mode 100644 storefront/components/profile/navigation.vue delete mode 100644 storefront/components/ui/counter.vue create mode 100644 storefront/composables/notification/index.ts create mode 100644 storefront/composables/notification/useNotification.ts create mode 100644 storefront/composables/orders/useOrderOverwrite.ts create mode 100644 storefront/composables/scrollTo/index.ts create mode 100644 storefront/composables/scrollTo/useScrollTo.ts create mode 100644 storefront/composables/wishlist/useWishlistOverwrite.ts create mode 100644 storefront/pages/profile.vue create mode 100644 storefront/pages/profile/cart.vue create mode 100644 storefront/pages/profile/orders.vue create mode 100644 storefront/pages/profile/settings.vue create mode 100644 storefront/pages/profile/wishlist.vue create mode 100644 storefront/stores/cart.ts diff --git a/storefront/app.vue b/storefront/app.vue index 6b3a5ff7..978334c4 100644 --- a/storefront/app.vue +++ b/storefront/app.vue @@ -23,6 +23,7 @@ import {useRefresh} from "~/composables/auth"; import {useLanguages} from "~/composables/languages"; import {useCompanyInfo} from "~/composables/company"; import {useCategories} from "~/composables/categories"; +import {useNotification} from "~/composables/notification"; const { locale } = useI18n(); const route = useRoute(); @@ -32,7 +33,13 @@ const switchLocalePath = useSwitchLocalePath(); const showBreadcrumbs = computed(() => { const name = typeof route.name === 'string' ? route.name : ''; - return !['index', 'brand', 'search'].some(prefix => name.startsWith(prefix)); + return ![ + 'index', + 'brand', + 'search', + 'profile', + 'activate-user' + ].some(prefix => name.startsWith(prefix)); }); const activeState = computed(() => appStore.activeState); @@ -66,7 +73,7 @@ watch( { immediate: true } ) -let stopWatcher: () => void; +let stopWatcher: VoidFunction = () => {} onMounted( async () => { refreshInterval = setInterval(async () => { diff --git a/storefront/assets/styles/main.scss b/storefront/assets/styles/main.scss index 57692cc7..328a3721 100644 --- a/storefront/assets/styles/main.scss +++ b/storefront/assets/styles/main.scss @@ -2,4 +2,8 @@ @use "modules/transitions"; @use "global/mixins"; @use "global/variables"; -@use "ui/collapse"; \ No newline at end of file + +// UI +@use "ui/collapse"; +@use "ui/notification"; +@use "ui/rating"; diff --git a/storefront/assets/styles/modules/normalize.scss b/storefront/assets/styles/modules/normalize.scss index b2cd8f49..1121d157 100644 --- a/storefront/assets/styles/modules/normalize.scss +++ b/storefront/assets/styles/modules/normalize.scss @@ -58,6 +58,10 @@ button:focus-visible { --el-skeleton-to-color: #c3c3c7 !important; } +.el-badge__content { + border: none !important; +} + @media (max-width: 1680px) { .container { max-width: 1200px; diff --git a/storefront/assets/styles/ui/collapse.scss b/storefront/assets/styles/ui/collapse.scss index ce7072a4..553f6394 100644 --- a/storefront/assets/styles/ui/collapse.scss +++ b/storefront/assets/styles/ui/collapse.scss @@ -36,6 +36,6 @@ flex-direction: column; gap: 5px; } -.el-icon { +.el-collapse .el-icon { display: none !important; } \ No newline at end of file diff --git a/storefront/assets/styles/ui/notification.scss b/storefront/assets/styles/ui/notification.scss new file mode 100644 index 00000000..48d39916 --- /dev/null +++ b/storefront/assets/styles/ui/notification.scss @@ -0,0 +1,39 @@ +@use "../global/variables" as *; + +.el-notification { + border: 2px solid $accent !important; + transition: all 0.3s ease !important; + + &__progress { + position: absolute; + left: 0; + bottom: 0; + width: 100%; + height: 3px; + background-color: $accentDark; + animation: progress-animation linear forwards; + } + + &__button { + margin-top: 10px; + padding: 6px 12px; + background-color: $accent; + border-radius: $default_border_radius; + color: #fff; + border: none; + cursor: pointer; + } + + .el-notification__closeBtn { + color: $accent !important; + } +} + +@keyframes progress-animation { + 0% { + width: 100%; + } + 100% { + width: 0; + } +} \ No newline at end of file diff --git a/storefront/assets/styles/ui/rating.scss b/storefront/assets/styles/ui/rating.scss new file mode 100644 index 00000000..9b3e764f --- /dev/null +++ b/storefront/assets/styles/ui/rating.scss @@ -0,0 +1,17 @@ +@use "../global/variables" as *; + +.el-rate .el-rate__icon.is-active { + color: $accent !important; +} +.el-rate .el-rate__icon { + color: #9a9a9a !important; + font-size: 20px !important; +} + +.white .el-rate__icon.is-active { + color: $white !important; + font-size: 24px !important; +} +.el-rate .el-rate__icon { + font-size: 24px !important; +} \ No newline at end of file diff --git a/storefront/components/base/header/catalog.vue b/storefront/components/base/header/catalog.vue index 44e8187d..5fa72dea 100644 --- a/storefront/components/base/header/catalog.vue +++ b/storefront/components/base/header/catalog.vue @@ -70,7 +70,6 @@ const setBlock = (state: boolean) => { } // TODO: add loading state -// TODO: fix displaying main part (children categories) const blockRef = ref(null) onClickOutside(blockRef, () => setBlock(false)) @@ -148,7 +147,7 @@ const setActiveCategory = (category: ICategory) => { &__block { display: grid; grid-template-columns: 20% 80%; - max-height: 60vh; + max-height: 50vh; } &__columns { diff --git a/storefront/components/base/header/index.vue b/storefront/components/base/header/index.vue index 4d740d68..b785e060 100644 --- a/storefront/components/base/header/index.vue +++ b/storefront/components/base/header/index.vue @@ -13,37 +13,33 @@
- -
- - - -
+ + + +

{{ t('header.actions.wishlist') }}

- -
- - - -
+ + + +

{{ t('header.actions.cart') }}

- -

{{ t('header.actions.profile') }}

+ +

{{ t('header.actions.profile') }}

- +

{{ t('header.actions.login') }}

@@ -64,20 +60,34 @@ \ No newline at end of file diff --git a/storefront/components/store/filter.vue b/storefront/components/store/filter.vue index cd7a78a1..951dd957 100644 --- a/storefront/components/store/filter.vue +++ b/storefront/components/store/filter.vue @@ -3,7 +3,7 @@

{{ t('store.filters.title') }}

-
{{ attribute.attributeName }} - {{ t('store.filters.all') }} @@ -40,7 +40,7 @@ :key="idx" :id="attribute.attributeName + idx" v-model="selectedMap[attribute.attributeName][value]" - :isFilter="true" + :isAccent="true" > {{ value }} @@ -67,6 +67,7 @@ \ No newline at end of file diff --git a/storefront/components/ui/input.vue b/storefront/components/ui/input.vue index 7274fcac..7d443bb4 100644 --- a/storefront/components/ui/input.vue +++ b/storefront/components/ui/input.vue @@ -10,74 +10,75 @@ class="block__input" >
-

{{ errorMessage }}

+

{{ errorMessage }}

\ No newline at end of file diff --git a/storefront/pages/profile.vue b/storefront/pages/profile.vue new file mode 100644 index 00000000..ff86af6b --- /dev/null +++ b/storefront/pages/profile.vue @@ -0,0 +1,46 @@ + + + + + \ No newline at end of file diff --git a/storefront/pages/profile/cart.vue b/storefront/pages/profile/cart.vue new file mode 100644 index 00000000..6be66978 --- /dev/null +++ b/storefront/pages/profile/cart.vue @@ -0,0 +1,87 @@ + + + + + \ No newline at end of file diff --git a/storefront/pages/profile/orders.vue b/storefront/pages/profile/orders.vue new file mode 100644 index 00000000..bcecaccf --- /dev/null +++ b/storefront/pages/profile/orders.vue @@ -0,0 +1,15 @@ + + + + + \ No newline at end of file diff --git a/storefront/pages/profile/settings.vue b/storefront/pages/profile/settings.vue new file mode 100644 index 00000000..3e3ad289 --- /dev/null +++ b/storefront/pages/profile/settings.vue @@ -0,0 +1,15 @@ + + + + + \ No newline at end of file diff --git a/storefront/pages/profile/wishlist.vue b/storefront/pages/profile/wishlist.vue new file mode 100644 index 00000000..72aadd00 --- /dev/null +++ b/storefront/pages/profile/wishlist.vue @@ -0,0 +1,175 @@ + + + + + \ No newline at end of file diff --git a/storefront/stores/cart.ts b/storefront/stores/cart.ts new file mode 100644 index 00000000..1afd293b --- /dev/null +++ b/storefront/stores/cart.ts @@ -0,0 +1,13 @@ +import type {IOrder} from "~/types"; + +export const useCartStore = defineStore('cart', () => { + const currentOrder = ref(null); + const setCurrentOrders = (order: IOrder) => { + currentOrder.value = order + }; + + return { + currentOrder, + setCurrentOrders + } +}) \ No newline at end of file diff --git a/storefront/types/api/orders.ts b/storefront/types/api/orders.ts index b67efecf..df7a1aed 100644 --- a/storefront/types/api/orders.ts +++ b/storefront/types/api/orders.ts @@ -6,4 +6,34 @@ export interface IOrderResponse { node: IOrder }[] } +} + +export interface IAddToOrderResponse { + addOrderProduct: { + order: IOrder + } +} + +export interface IRemoveFromOrderResponse { + removeOrderProduct: { + order: IOrder + } +} + +export interface IRemoveKindFromOrderResponse { + removeOrderProductsOfAKind: { + order: IOrder + } +} + +export interface IRemoveAllFromOrderResponse { + removeAllOrderProducts: { + order: IOrder + } +} + +export interface IBulkOrderResponse { + bulkOrderAction: { + order: IOrder + } } \ No newline at end of file diff --git a/storefront/types/api/wishlist.ts b/storefront/types/api/wishlist.ts index 92c9db1f..826f78ff 100644 --- a/storefront/types/api/wishlist.ts +++ b/storefront/types/api/wishlist.ts @@ -6,4 +6,28 @@ export interface IWishlistResponse { node: IWishlist }[] } +} + +export interface IAddToWishlistResponse { + addWishlistProduct: { + wishlist: IWishlist + } +} + +export interface IRemoveFromWishlistResponse { + removeWishlistProduct: { + wishlist: IWishlist + } +} + +export interface IRemoveAllFromWishlistResponse { + removeAllWishlistProducts: { + wishlist: IWishlist + } +} + +export interface IBulkWishlistResponse { + bulkWishlistAction: { + wishlist: IWishlist + } } \ No newline at end of file diff --git a/storefront/types/app/products.ts b/storefront/types/app/products.ts index 02529d29..9d8ce2d7 100644 --- a/storefront/types/app/products.ts +++ b/storefront/types/app/products.ts @@ -4,6 +4,12 @@ export interface IProduct { price: number, quantity: number, slug: string, + description: string, + brand: { + smallLogo: string, + uuid: string, + name: string + } category: { name: string slug: string, @@ -27,8 +33,8 @@ export interface IProduct { values: { value: string, uuid: string - } - } + }[] + }[] } }[] }, diff --git a/storefront/types/app/user.ts b/storefront/types/app/user.ts index a3568f14..be3bf3b9 100644 --- a/storefront/types/app/user.ts +++ b/storefront/types/app/user.ts @@ -7,6 +7,7 @@ export interface IUser { firstName: string, lastName: string, phoneNumber: string, + dateJoined: string, balance: { amount: number, }