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

Commit

Permalink
feat: dummy checkout (#357)
Browse files Browse the repository at this point in the history
* feat: enable placing an order for logged in user; redirect to success page

* fix: global date format (minutes)

* refactor(theme): split ReviewOrder into smaller parts

* feat(client): place an order for logged in and guest users

* feat(composables): refactor isLoggedIn, handle placing an order

* refactor(defaul-theme): split views into components, delete unused imports

* docs(client): createGuestOrder and createOrder added
  • Loading branch information
mkucmus authored Feb 12, 2020
1 parent 4d7f400 commit e01df57
Show file tree
Hide file tree
Showing 38 changed files with 2,810 additions and 33 deletions.
6 changes: 2 additions & 4 deletions api/helpers.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,10 +74,8 @@ export const getFilterSearchCriteria: (selectedFilters: any) => any[];
// @alpha (undocumented)
export function getNavigationRoutes(navigationElements: NavigationElement[]): NavigationRoute[];

// @alpha (undocumented)
export function getProductMainImageUrl({ product }?: {
product?: Product;
}): string;
// @alpha
export function getProductMainImageUrl(product: Product): string;

// @alpha (undocumented)
export function getProductMediaGallery({ product }?: {
Expand Down
6 changes: 6 additions & 0 deletions api/shopware-6-client.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,12 @@ export interface ConfigChangedArgs {
// @alpha
export function createCustomerAddress(params: CustomerAddressParam): Promise<string>;

// @alpha
export function createGuestOrder(email: string): Promise<Order>;

// @alpha
export function createOrder(): Promise<Order>;

// @alpha (undocumented)
export interface CustomerAddressParam extends Partial<CustomerAddress> {
}
Expand Down
61 changes: 59 additions & 2 deletions packages/composables/__tests__/useCart.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,24 @@ const mockedShopwareClient = shopwareClient as jest.Mocked<

describe("Composables - useCart", () => {
const stateCart: Ref<Object | null> = ref(null);
const stateUser: Ref<Object | null> = ref(null);
beforeEach(() => {
// mock vuex store
jest.resetAllMocks();
stateCart.value = null;
stateUser.value = null;
setStore({
getters: reactive({ getCart: computed(() => stateCart.value) }),
getters: reactive({
getCart: computed(() => stateCart.value),
getUser: computed(() => stateUser.value)
}),
commit: (name: string, value: any) => {
stateCart.value = value;
if (name === "SET_CART") {
stateCart.value = value;
}
if (name === "SET_USER") {
stateUser.value = value;
}
}
});
});
Expand Down Expand Up @@ -101,9 +111,56 @@ describe("Composables - useCart", () => {
expect(totalPrice.value).toEqual(123);
});
});
describe("subtotal", () => {
it("should show items totalPrice as 0", () => {
const { subtotal } = useCart();
expect(subtotal.value).toEqual(0);
});

it("should show 0 on empty price object", () => {
stateCart.value = {
price: {}
};
const { subtotal } = useCart();
expect(subtotal.value).toEqual(0);
});

it("should show correct subtotal price", () => {
stateCart.value = {
price: { positionPrice: 123 }
};
const { subtotal } = useCart();
expect(subtotal.value).toEqual(123);
});
});
});

describe("methods", () => {
describe("placeOrder", () => {
it("should assign the appropriate error if user email is unknown or is not logged in", async () => {
const { error, placeOrder } = useCart();
await placeOrder();
expect(error.value).toStrictEqual({
message: "Order cannot be placed"
});
});
it("should try to place an order if user is logged in and return the order object", async () => {
mockedShopwareClient.createOrder.mockResolvedValueOnce({
id: "some-order-id-123456"
} as any);
stateUser.value = {
id: "user-id-8754321",
email: "test@email.com"
} as any;

const { error, placeOrder } = useCart();
const result = await placeOrder();
expect(mockedShopwareClient.createOrder).toBeCalledTimes(1);
expect(mockedShopwareClient.createOrder).toBeCalledWith();
expect(error.value).toBeFalsy();
expect(result).toHaveProperty("id");
});
});
describe("refreshCart", () => {
it("should correctly refresh the cart", async () => {
const { count, refreshCart } = useCart();
Expand Down
31 changes: 29 additions & 2 deletions packages/composables/src/hooks/useCart/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,20 @@ import {
getCart,
addProductToCart,
removeCartItem,
changeCartItemQuantity
changeCartItemQuantity,
createOrder
} from "@shopware-pwa/shopware-6-client";
import { getStore } from "../..";
import { useUser } from "../useUser";
import { Order } from "@shopware-pwa/shopware-6-client/src/interfaces/models/checkout/order/Order";
import { ClientApiError } from "@shopware-pwa/shopware-6-client/src/interfaces/errors/ApiError";

/**
* @alpha
*/
export const useCart = (): any => {
let vuexStore = getStore();
const { isLoggedIn } = useUser();
const loading: Ref<boolean> = ref(false);
const error: Ref<any> = ref(null);

Expand Down Expand Up @@ -45,6 +49,22 @@ export const useCart = (): any => {
vuexStore.commit("SET_CART", result);
}

/**
* todo: move this method to the separated composable after the implementation of dummy checkout.
*/
async function placeOrder(): Promise<Order | undefined> {
if (isLoggedIn.value) {
return createOrder();
}

// TODO: related https://github.com/DivanteLtd/shopware-pwa/issues/375
// return createGuestOrder(guestUserEmail);

error.value = {
message: "Order cannot be placed"
};
}

const cart = computed(() => {
return vuexStore.getters.getCart;
});
Expand All @@ -66,6 +86,11 @@ export const useCart = (): any => {
return cartPrice || 0;
});

const subtotal = computed(() => {
const cartPrice = cart.value?.price?.positionPrice;
return cartPrice || 0;
});

return {
addProduct,
cart,
Expand All @@ -76,6 +101,8 @@ export const useCart = (): any => {
loading,
refreshCart,
removeProduct,
totalPrice
totalPrice,
subtotal,
placeOrder
};
};
2 changes: 1 addition & 1 deletion packages/composables/src/hooks/useUser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,7 @@ export const useUser = (): UseUser => {
return true;
};

const isLoggedIn = computed(() => !!user.value);
const isLoggedIn = computed(() => !!user.value?.id);

return {
login,
Expand Down
3 changes: 3 additions & 0 deletions packages/default-theme/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -88,3 +88,6 @@ sw.*

# Vim swap files
*.swp

cypress/screenshots
cypress/videos
11 changes: 9 additions & 2 deletions packages/default-theme/components/SwCart.vue
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
<SfPrice :regular="totalPrice | price" class="sf-price--big" />
</template>
</SfProperty>
<SfButton class="sf-button--full-width">Go to checkout</SfButton>
<SfButton class="sf-button--full-width" aria-label="go-to-checkout" @click="goToCheckout()">Go to checkout</SfButton>
</div>
<div v-else key="empty-cart" class="empty-cart">
<div class="empty-cart__banner">
Expand All @@ -49,6 +49,7 @@
import { SfSidebar, SfButton, SfProperty, SfPrice } from '@storefront-ui/vue'
import { useCart, useCartSidebar } from '@shopware-pwa/composables'
import SwCartProduct from './SwCartProduct'
import { PAGE_CHECKOUT } from '../helpers/pages'
export default {
name: 'Cart',
Expand Down Expand Up @@ -76,7 +77,13 @@ export default {
if (!price) return
return `$${price}`
}
}
},
methods: {
goToCheckout() {
this.toggleSidebar();
return this.$router.push(PAGE_CHECKOUT);
}
},
}
</script>
<style lang="scss" scoped>
Expand Down
33 changes: 31 additions & 2 deletions packages/default-theme/components/SwCartProduct.vue
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ export default {
const quantity = ref(props.product.quantity)
const productImage = computed(() =>
getProductMainImageUrl({ product: props.product })
getProductMainImageUrl(props.product)
)
watch(quantity, async (qty) => {
Expand All @@ -78,7 +78,36 @@ export default {
removeProduct,
quantity
}
}
},
computed: {
getName() {
return getProductName({ product: this.product })
},
getProductRating() {
return this.product && this.product.ratingAverage
},
// should be replaced with prettyUrl attribute when pretty urls are included in product entity
getRouterLink() {
return getProductUrl(this.product)
},
getRegularPrice() {
const regular = getProductRegularPrice({ product: this.product })
const special = getProductSpecialPrice(this.product)
// temporary fix to show proper regular price
return '$' + (regular > special ? regular : special)
},
getSpecialPrice() {
const special = getProductSpecialPrice(this.product)
const regular = getProductRegularPrice({ product: this.product })
// temporary fix to show proper special price
return special && '$' + (special < regular ? special : regular)
},
getImageUrl() {
return (
getProductMainImageUrl(this.product)
)
}
},
}
</script>
<style lang="scss" scoped>
Expand Down
2 changes: 1 addition & 1 deletion packages/default-theme/components/SwProductCard.vue
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ export default {
},
getImageUrl() {
return (
getProductMainImageUrl({ product: this.product }) ||
getProductMainImageUrl(this.product) ||
require('~/assets/productB.jpg')
)
}
Expand Down
3 changes: 2 additions & 1 deletion packages/default-theme/components/TopNavigation.vue
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ import {
useNavigation
} from '@shopware-pwa/composables'
import SwLoginModal from './modals/SwLoginModal'
import { PAGE_ACCOUNT } from '../helpers/pages'
export default {
components: { SfHeader, SfCircleIcon, SfBadge, SwLoginModal, SfImage },
Expand Down Expand Up @@ -113,7 +114,7 @@ export default {
},
methods: {
async userIconClick() {
if (this.isLoggedIn) this.$router.push('account')
if (this.isLoggedIn) this.$router.push(PAGE_ACCOUNT)
else this.toggleModal()
}
}
Expand Down
Loading

1 comment on commit e01df57

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Deploy preview for website ready!

Built with commit faf1eff

https://shopware-pwa-2q3sp78ll.now.sh

Please sign in to comment.