diff --git a/storefront/app/components/base/footer/index.vue b/storefront/app/components/base/footer/index.vue index ba67b4c6..b1466398 100644 --- a/storefront/app/components/base/footer/index.vue +++ b/storefront/app/components/base/footer/index.vue @@ -103,7 +103,7 @@ const encodedCompanyAddress = computed(() => { gap: 14px; & h6 { - color: $link_primary; + color: #d2d0d0; font-size: 16px; font-weight: 600; letter-spacing: -0.5px; diff --git a/storefront/app/composables/orders/useOrderBuy.ts b/storefront/app/composables/orders/useOrderBuy.ts index 26eab131..5812a129 100644 --- a/storefront/app/composables/orders/useOrderBuy.ts +++ b/storefront/app/composables/orders/useOrderBuy.ts @@ -10,10 +10,12 @@ export function useOrderBuy() { const { mutate, loading, error } = useMutation(BUY_CART); - async function buyOrder() { + async function buyOrder(promocodeUuid?: string) { const result = await mutate({ orderUuid: orderUuid.value, forcePayment: true, + forceBalance: false, + promocodeUuid: promocodeUuid }); if (result?.data?.buyOrder?.transaction?.process?.url) { diff --git a/storefront/app/graphql/mutations/cart.ts b/storefront/app/graphql/mutations/cart.ts index 913fd656..99eb19e4 100644 --- a/storefront/app/graphql/mutations/cart.ts +++ b/storefront/app/graphql/mutations/cart.ts @@ -88,11 +88,15 @@ export const BULK_CART = gql` export const BUY_CART = gql` mutation buyOrder( $orderUuid: String!, - $forcePayment: Boolean! + $forcePayment: Boolean, + $forceBalance: Boolean, + $promocodeUuid: String, ) { buyOrder( orderUuid: $orderUuid forcePayment: $forcePayment + forceBalance: $forceBalance + promocodeUuid: $promocodeUuid ) { transaction { amount diff --git a/storefront/app/pages/cart.vue b/storefront/app/pages/cart.vue index 267da952..14112de3 100644 --- a/storefront/app/pages/cart.vue +++ b/storefront/app/pages/cart.vue @@ -2,35 +2,61 @@
-
-

{{ t('cart.title') }}

-
- -

({{ t('cart.items', productsInCartQuantity, { count: productsInCartQuantity }) }})

-
-

{{ totalPrice }}$

- - - {{ t('buttons.checkout') }} - -
-
- -
-
- +
+

{{ t('cart.title') }}

+ +
+
+ +
+

{{ t('cart.empty') }}

-

{{ t('cart.empty') }}

+
+
+
+

{{ t('cart.checkout') }}

+ +

{{ t('cart.items', productsInCartQuantity, { count: productsInCartQuantity }) }}

+
+
{{ t('cart.totalPrice') }}: {{ totalPrice }}$
+
+ + + +
- + + + {{ t('buttons.checkout') }} + +
@@ -44,10 +70,13 @@ import {useExactProducts} from "@composables/products/useExactProducts"; const {t} = useI18n(); const cartStore = useCartStore(); const userStore = useUserStore(); +const promocodeStore = usePromocodeStore(); const { $appHelpers } = useNuxtApp(); const isAuthenticated = computed(() => userStore.isAuthenticated); +const promocodes = computed(() => promocodeStore.promocodes); + const cookieCart = useCookie($appHelpers.COOKIES_CART_KEY, { default: () => [], path: '/', @@ -56,6 +85,20 @@ const cookieCart = useCookie($appHelpers.COOKIES_CART_KEY, { const { buyOrder } = useOrderBuy(); const { products, getExactProducts } = useExactProducts(); +const menu = ref(null); +const button = ref(null); +const isMenuVisible = ref(false); +const setMenuVisible = (state) => { + isMenuVisible.value = state; +}; +onClickOutside(menu, () => setMenuVisible(false), { ignore: [button] }); + +const selectedPromo = ref(null); +const selectPromo = (promo) => { + setMenuVisible(false); + selectedPromo.value = promo; +}; + const cartUuids = computed(() => { return cookieCart.value.map(item => item.productUuid); }); @@ -121,20 +164,15 @@ setPageTitle(t('breadcrumbs.cart')); &__wrapper { display: flex; - flex-direction: column; + align-items: flex-start; gap: 50px; } - &__top { + &__main { + width: 100%; display: flex; - align-items: center; - justify-content: space-between; - - &-inner { - display: flex; - align-items: center; - gap: 35px; - } + flex-direction: column; + gap: 50px; &-title { color: $primary_dark; @@ -143,18 +181,6 @@ setPageTitle(t('breadcrumbs.cart')); font-weight: 600; letter-spacing: -0.5px; } - - & p { - color: $text; - font-size: 18px; - font-weight: 400; - letter-spacing: -0.5px; - } - - &-button { - width: fit-content; - padding-inline: 25px; - } } &__list { @@ -165,6 +191,119 @@ setPageTitle(t('breadcrumbs.cart')); } } + &__checkout { + width: 300px; + flex-shrink: 0; + display: flex; + flex-direction: column; + gap: 15px; + border: 1px solid $border; + border-radius: $default_border_radius; + padding: 20px; + + & h2 { + margin-bottom: 20px; + color: $primary; + font-size: 24px; + font-weight: 700; + } + + & p { + color: $text; + font-size: 18px; + font-weight: 400; + letter-spacing: -0.5px; + } + + & h6 { + color: $primary; + font-size: 18px; + font-weight: 500; + + & span { + font-weight: 700; + } + } + + &-promo { + width: 100%; + position: relative; + + & .current { + width: 100%; + border-radius: $default_border_radius; + padding: 8px 12px; + font-size: 16px; + border: 1px solid $border; + display: flex; + align-items: center; + justify-content: space-between; + + font-weight: 500; + color: $text; + } + + & .menu { + position: absolute; + z-index: 2; + left: 0; + width: 100%; + top: 115%; + background-color: $main; + padding: 5px 0; + border-radius: $default_border_radius; + border: 1px solid $border; + max-height: 300px; + overflow-y: auto; + + &__list { + width: 100%; + display: flex; + flex-direction: column; + align-items: start; + + &-item { + cursor: pointer; + width: 100%; + padding: 6px 10px; + display: flex; + align-items: center; + gap: 10px; + justify-content: space-between; + + color: $text; + + @include hover { + background-color: $link_secondary; + } + + & .code { + font-weight: 500; + } + + & .value { + font-weight: 700; + color: $primary; + } + } + } + + & .empty { + padding: 4px 12px; + + font-size: 14px; + font-weight: 500; + color: $text; + } + } + } + + &-button { + margin-top: 20px; + padding-inline: 25px; + } + } + &__empty { font-weight: 500; font-size: 18px; diff --git a/storefront/i18n/locales/en-gb.json b/storefront/i18n/locales/en-gb.json index fc44c8a5..56f3d526 100644 --- a/storefront/i18n/locales/en-gb.json +++ b/storefront/i18n/locales/en-gb.json @@ -48,7 +48,8 @@ "newPassword": "New password", "confirmPassword": "Confirm password", "confirmNewPassword": "Confirm new password", - "brandsSearch": "Search brands by name..." + "brandsSearch": "Search brands by name...", + "promocode": "Enter promocode" }, "checkboxes": { "remember": "Remember me", @@ -332,9 +333,15 @@ "text": "Discover the latest trends, style inspiration, and fashion insights from our editorial team." }, "cart": { + "totalPrice": "Total price", "title": "My Cart", "items": "no items | {count} item | {count} items", - "empty": "Your cart is empty." + "empty": "Your cart is empty.", + "checkout": "Checkout", + "promocode": { + "apply": "Apply a promocode", + "empty": "You don't have any promocodes" + } }, "wishlist": { "title": "My Wishlist", diff --git a/storefront/i18n/locales/ru-ru.json b/storefront/i18n/locales/ru-ru.json index fb95c107..75b56de5 100644 --- a/storefront/i18n/locales/ru-ru.json +++ b/storefront/i18n/locales/ru-ru.json @@ -48,7 +48,8 @@ "newPassword": "Новый пароль", "confirmPassword": "Подтвердите пароль", "confirmNewPassword": "Подтвердите новый пароль", - "brandsSearch": "Поиск брендов по названию..." + "brandsSearch": "Поиск брендов по названию...", + "promocode": "Введите промокод" }, "checkboxes": { "remember": "Запомнить меня", @@ -332,9 +333,15 @@ "text": "Узнавайте о последних трендах, источниках вдохновения для стиля и модных инсайтах от нашей редакции." }, "cart": { + "totalPrice": "Итог", "title": "Моя корзина", "items": "нет товаров | {count} товар | {count} товара | {count} товаров", - "empty": "Ваша корзина пуста" + "empty": "Ваша корзина пуста", + "checkout": "Оформление", + "promocode": { + "apply": "Примените промокод", + "empty": "У вас нет промокодов" + } }, "wishlist": { "title": "Мои Избранные",