Skip to content
This repository has been archived by the owner on Oct 31, 2024. It is now read-only.

feat(default-theme): new checkout flow #1502

Merged
merged 11 commits into from
May 20, 2021
Merged
9 changes: 9 additions & 0 deletions docs/landing/operations/migrations/0.8.x_to_0.9.x.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,3 +71,12 @@ Basic migration has 3 steps:
## [default-theme] Upgrading to Storefront-ui v0.10 (potential Breaking Change)

With this release, we upgraded storefront-ui to the newest version. This required style improvements and changes in multiple components. Potentially it may break some styling in your overwritten components, shouldn't be anything too hard to fix though.

## [default-theme] Extended checkout's payment flow

Following flow from https://github.com/vuestorefront/shopware-pwa/issues/1419 the payment flow has changed in terms of how the customer is being redirected. When the selected payment method implements async payment - once the order is placed the customer is being redirected immediately to the external payment gateway. Depending on a result of the payment the customer is redirected back in both scenarios: failure and success to the corresponding routes:

- /order-success - when the payment was done without any problems, or the payment does not require additional redirections to the external providers.
- /payment-failure - when the payment gateway tells the API the payment isn't finished properly.

In case of problems during placing an order itself - no redirection is made, just appriopriate notifications are shown on the review step.
63 changes: 23 additions & 40 deletions packages/default-theme/src/components/SwOrderDetails.vue
Original file line number Diff line number Diff line change
Expand Up @@ -75,25 +75,7 @@
>
<template #loader>{{ $t("Checking payment status...") }}</template>
<div v-if="paymentUrl">
<SfModal
v-if="!preventRedirect"
class="sw-modal"
:title="$t('Add address')"
:visible="isModalOpen"
@close="isModalOpen = false"
>
<SfCharacteristic
sizeIcon="xl"
icon="credits"
:title="$t('Payment in 5 seconds...')"
:description="
$t(
'You will be redirected to the payment gateway in 5 seconds...'
)
"
/>
</SfModal>
<a v-if="preventRedirect" :href="paymentUrl">
<a :href="paymentUrl">
<SwButton
class="sf-button sf-button--full-width pay-button color-danger"
>
Expand All @@ -115,7 +97,11 @@ import {
SfCharacteristic,
SfModal,
} from "@storefront-ui/vue"
import { useUser, getApplicationContext } from "@shopware-pwa/composables"
import {
useNotifications,
useUser,
getApplicationContext,
} from "@shopware-pwa/composables"
import { ref, onMounted, computed, watch } from "@vue/composition-api"
import SwPluginSlot from "sw-plugins/SwPluginSlot.vue"
import {
Expand All @@ -128,12 +114,12 @@ import {
getStoreOrderPaymentUrl,
} from "@shopware-pwa/shopware-6-client"
import SwButton from "@/components/atoms/SwButton.vue"
import { PAGE_ORDER_SUCCESS } from "@/helpers/pages"
import SwOrderDetailsItem from "@/components/SwOrderDetailsItem.vue"
import SwPersonalDetails from "@/components/SwPersonalDetails.vue"
import SwAddress from "@/components/SwAddress.vue"
import SwCheckoutMethod from "@/components/SwCheckoutMethod.vue"
import SwTotals from "@/components/SwTotals.vue"
import { PAGE_ORDER_SUCCESS, PAGE_ORDER_PAYMENT_FAILURE } from "@/helpers/pages"

export default {
name: "SwOrderDetails",
Expand Down Expand Up @@ -175,9 +161,10 @@ export default {
},
// TODO: move this logic into separate service;
// details: https://github.com/DivanteLtd/shopware-pwa/issues/781
setup({ orderId, preventRedirect }, { root }) {
setup({ orderId }, { root }) {
const { apiInstance } = getApplicationContext(root, "SwOrderDetails")
const { getOrderDetails, loading, error: userError } = useUser(root)
const { pushWarning } = useNotifications(root)
const order = ref(null)
const paymentMethod = computed(
() => order.value?.transactions?.[0]?.paymentMethod
Expand All @@ -187,7 +174,6 @@ export default {
)
const paymentUrl = ref(null)
const isPaymentButtonLoading = ref(false)
const isModalOpen = ref(false)

const personalDetails = computed(
() =>
Expand Down Expand Up @@ -225,28 +211,27 @@ export default {
isPaymentButtonLoading.value = true
order.value = await getOrderDetails(orderId)
const resp = await getStoreOrderPaymentUrl(
{
orderId,
finishUrl: `${window.location.origin}${PAGE_ORDER_SUCCESS}?orderId=${orderId}`,
},
orderId,
root.$routing.getAbsoluteUrl(
`${PAGE_ORDER_SUCCESS}?orderId=${orderId}`
),
root.$routing.getAbsoluteUrl(
`${PAGE_ORDER_PAYMENT_FAILURE}?orderId=${orderId}`
),
apiInstance
)
paymentUrl.value = resp.redirectUrl
} catch (e) {}
isPaymentButtonLoading.value = false
})

watch(paymentUrl, (paymentUrl, prevPaymentUrl) => {
if (paymentUrl && window && !preventRedirect) {
isModalOpen.value = true
setTimeout(() => {
window.location.href = paymentUrl
}, 5000)
} catch (e) {
pushWarning(
root.$t(
"An error occred during checking the payment status. Please try again later."
)
)
}
isPaymentButtonLoading.value = false
})

return {
isLoading: loading,
userError,
order,
personalDetails,
Expand All @@ -260,7 +245,6 @@ export default {
status,
paymentUrl,
isPaymentButtonLoading,
isModalOpen,
}
},
}
Expand All @@ -283,7 +267,6 @@ export default {

&__loader {
margin-top: var(--spacer-base);
height: 3rem;
}

&__header {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -347,7 +347,7 @@ export default {
city: state.city,
street: state.street,
zipcode: state.zipcode,
countryId: state.countryId,
countryId: state.countryId || countryId.value,
},
})
isSuccess && emit("success")
Expand Down
3 changes: 2 additions & 1 deletion packages/default-theme/src/helpers/pages.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,6 @@ export const PAGE_CHECKOUT = "/checkout"
export const PAGE_ACCOUNT = "/account/profile"
export const PAGE_LOGIN = "/login"
export const PAGE_SEARCH = "/search"
export const PAGE_ORDER_SUCCESS = "/order"
export const PAGE_ORDER_SUCCESS = "/order-success"
export const PAGE_ORDER_PAYMENT_FAILURE = "/payment-failure"
export const PAGE_WISHLIST = "/wishlist"
143 changes: 143 additions & 0 deletions packages/default-theme/src/layouts/checkoutLayout.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
<template>
<div class="layout">
<SwNotifications />
<SwOfflineMode />
<SwPluginSlot name="page-top" />
<SfHeader
:title="$t('page.title')"
class="sw-header sf-header--has-mobile-search"
:has-mobile-search="false"
:is-sticky="false"
>
<template #logo>
<SwLogo />
</template>
<template #navigation> </template>
<template #search>
<div />
</template>
<template #header-icons>
<div />
</template>
</SfHeader>

<SwPluginSlot name="top-header-after" />
<SwPluginSlot name="breadcrumbs" :slot-context="getBreadcrumbs">
<SfBreadcrumbs
v-show="getBreadcrumbs.length > 0"
:breadcrumbs="getBreadcrumbs"
class="sw-breadcrumbs layout__sized"
@click="redirectTo"
/>
</SwPluginSlot>

<nuxt />
<SwCart v-if="isSidebarOpen" />
<SwLoginModal
:is-open="isLoginModalOpen"
@close="switchLoginModalState(false)"
/>
<div class="layout__bottom-navigation-placeholder" />
<SwBottomNavigation class="layout__bottom-navigation" />
</div>
</template>

<script>
import { SfBreadcrumbs, SfHeader } from "@storefront-ui/vue"
import SwBottomNavigation from "@/components/SwBottomNavigation.vue"
import SwPluginSlot from "sw-plugins/SwPluginSlot.vue"
import { useBreadcrumbs, useUIState } from "@shopware-pwa/composables"
import { computed, ref, watchEffect } from "@vue/composition-api"
import SwLoginModal from "@/components/modals/SwLoginModal.vue"
import SwNotifications from "@/components/SwNotifications.vue"
import SwOfflineMode from "@/components/SwOfflineMode.vue"
import SwLogo from "@/components/SwLogo.vue"
const SwCart = () => import("@/components/SwCart.vue")

export default {
components: {
SfBreadcrumbs,
SwBottomNavigation,
SwPluginSlot,
SwLoginModal,
SwNotifications,
SwOfflineMode,
SfHeader,
SwLogo,
SwCart,
},

setup(props, { root }) {
const { breadcrumbs } = useBreadcrumbs(root)
const { isOpen: isSidebarOpen } = useUIState(root, "CART_SIDEBAR_STATE")
const { isOpen: isLoginModalOpen, switchState: switchLoginModalState } =
useUIState(root, "LOGIN_MODAL_STATE")

// Load cart component only when needed
const loadSidebarComponent = ref(isSidebarOpen.value)
const stopWatcher = watchEffect(() => {
if (isSidebarOpen.value) {
loadSidebarComponent.value = isSidebarOpen.value
stopWatcher()
}
})

const getBreadcrumbs = computed(() => {
return breadcrumbs.value.map((breadcrumb) => {
return {
// map to SFUI type
text: breadcrumb.name,
link: root.$routing.getUrl(breadcrumb.path),
}
})
})

return {
getBreadcrumbs,
isSidebarOpen: loadSidebarComponent,
isLoginModalOpen,
switchLoginModalState,
}
},
middleware: ["pages"],
methods: {
redirectTo(route) {
return this.$router.push(this.$routing.getUrl(route.link))
},
},
}
</script>

<style lang="scss" scoped>
@import "@/assets/scss/variables";

.layout {
box-sizing: border-box;
height: 100%;

&__bottom-navigation-placeholder {
height: 6em;
@include for-desktop() {
display: none;
}
}
&__bottom-navigation {
@include for-desktop() {
display: none;
}
}

&__sized {
@include for-desktop {
max-width: 1320px;
width: 100%;
margin: auto;
}
}
}

.sw-breadcrumbs {
box-sizing: border-box;
padding: 1rem;
}
</style>
8 changes: 6 additions & 2 deletions packages/default-theme/src/locales/de-DE.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
"Edit": "Bearbeiten",
"Email is required": "E-Mail ist erforderlich",
"Empty bag": "Leere Tasche",
"Encountered problems": "Probleme gestoßen:",
"Encountered problems": "Probleme gestoßen",
"Enjoy these perks with your free account!": "Genießen Sie diese Vergünstigungen mit Ihrem kostenlosen Konto!",
"Faster checkout": "Schnellerer Checkout",
"Feel free to edit any of your details below so your account is always up to date": "Sie können jederzeit Ihre Angaben unten bearbeiten, damit Ihr Kundenkonto immer auf dem neuesten Stand ist.",
Expand Down Expand Up @@ -213,5 +213,9 @@
"Newsletter subscription": "Newsletter-Abonnement",
"Great! Your new password has been set.": "Groß! Ihr neues Passwort wurde festgelegt.",
"Reset password": "Passwort zurücksetzen",
"Set new password": "Neues Passwort setzen"
"Set new password": "Neues Passwort setzen",
"An error occred during checking the payment status. Please try again later.":"Beim Überprüfen des Zahlungsstatus ist ein Fehler aufgetreten. Bitte versuchen Sie es später noch einmal.",
"Your order is being created.": "Ihre Bestellung wird erstellt",
"Please wait...": "Warten Sie mal...",
"Your order cannot be placed. Please try again later.": "Ihre Bestellung kann nicht aufgegeben werden. Bitte versuchen Sie es später noch einmal."
}
8 changes: 6 additions & 2 deletions packages/default-theme/src/locales/en-GB.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
"Edit": "Edit",
"Email is required": "Email is required",
"Empty bag": "Empty bag",
"Encountered problems": "Encountered problems:",
"Encountered problems": "Encountered problems",
"Enjoy these perks with your free account!": "Enjoy these perks with your free account!",
"Faster checkout": "Faster checkout",
"Feel free to edit any of your details below so your account is always up to date": "Feel free to edit any of your details below so your account is always up to date",
Expand Down Expand Up @@ -219,5 +219,9 @@
"Newsletter subscription": "Newsletter subscription",
"Great! Your new password has been set.": "Great! Your new password has been set.",
"Reset password": "Reset password",
"Set new password": "Set new password"
"Set new password": "Set new password",
"An error occred during checking the payment status. Please try again later.":"An error occred during checking the payment status. Please try again later.",
"Your order is being created.": "Your order is being created.",
"Please wait...": "Please wait...",
"Your order cannot be placed. Please try again later.": "Your order cannot be placed. Please try again later."
}
8 changes: 6 additions & 2 deletions packages/default-theme/src/locales/it-IT.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
"Edit": "Modifica",
"Email is required": "L'e-mail è necessaria",
"Empty bag": "Borsa vuota",
"Encountered problems": "Problemi incontrati:",
"Encountered problems": "Problemi incontrati",
"Enjoy these perks with your free account!": "Goditi questi vantaggi con il tuo account gratuito!",
"Faster checkout": "Pagamento più veloce",
"Feel free to edit any of your details below so your account is always up to date": "Sentiti libero di modificare i tuoi dati qui sotto in modo che il tuo account sia sempre aggiornato",
Expand Down Expand Up @@ -218,5 +218,9 @@
"Newsletter subscription": "Sottoscrizione alla Newsletter",
"Great! Your new password has been set.": "Grande! La tua nuova password è stata impostata.",
"Reset password": "Resetta la password",
"Set new password": "Impostare una nuova password"
"Set new password": "Impostare una nuova password",
"An error occred during checking the payment status. Please try again later.":"Si è verificato un errore durante la verifica dello stato del pagamento. Per favore riprova più tardi.",
"Your order is being created.": "Il tuo ordine è in fase di creazione",
"Please wait...": "Attendere prego...",
"Your order cannot be placed. Please try again later.": "Il tuo ordine non può essere effettuato. Per favore riprova più tardi."
}
8 changes: 6 additions & 2 deletions packages/default-theme/src/locales/pl-PL.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
"Edit": "Edytuj",
"Email is required": "Wymagany jest e-mail",
"Empty bag": "Pusta torba",
"Encountered problems": "Napotkane problemy:",
"Encountered problems": "Napotkane problemy",
"Enjoy these perks with your free account!": "Korzystaj z tych udogodnień dzięki darmowemu kontu!",
"Faster checkout": "Szybsza kasa",
"Feel free to edit any of your details below so your account is always up to date": "Nie krępuj się edytować swoich danych poniżej, aby Twoje konto było zawsze aktualne",
Expand Down Expand Up @@ -218,5 +218,9 @@
"Newsletter subscription": "Zapis do newslettera",
"Great! Your new password has been set.": "Świetnie! Ustawiłeś swoje nowe hasło.",
"Reset password": "Resetowanie hasła",
"Set new password": "Ustaw nowe hasło"
"Set new password": "Ustaw nowe hasło",
"An error occred during checking the payment status. Please try again later.":"Wystąpił błąd podczas sprawdzania statusu płatności. Spróbuj ponownie później.",
"Your order is being created.": "Trwa składanie Twojego zamówienia.",
"Please wait...": "To zajmie tylko chwilę...",
"Your order cannot be placed. Please try again later.": "Zamówienie nie może zostać złożone. Spróbuj ponownie za chwilę."
}
Loading