Skip to content

Commit

Permalink
feat: #49 (*) adjust billing shipping
Browse files Browse the repository at this point in the history
  • Loading branch information
Baroshem committed Aug 21, 2021
1 parent 088f0d4 commit c03bf85
Show file tree
Hide file tree
Showing 12 changed files with 269 additions and 121 deletions.
4 changes: 2 additions & 2 deletions packages/api-client/src/api/getShippingMethods/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import gql from 'graphql-tag';
import eligibleShippingMethodsQuery from './eligibleShippingMethodsQuery';
import { CustomQuery } from '@vue-storefront/core';
import { Context, RequestDataStructure, GetShippingMethodsResponse, PaymentMethodQuote } from '../../types';
import { Context, RequestDataStructure, GetShippingMethodsResponse, ShippingMethodQuote } from '../../types';

const getShippingMethods = async (context: Context, customQuery?: CustomQuery): Promise<GetShippingMethodsResponse> => {
const getShippingMethods = {};
Expand All @@ -10,7 +10,7 @@ const getShippingMethods = async (context: Context, customQuery?: CustomQuery):
customQuery, { eligibleShippingMethods: { query: eligibleShippingMethodsQuery, variables: getShippingMethods } }
);

const request = await context.client.query<RequestDataStructure<'eligiblePaymentMethods', PaymentMethodQuote[]>>({
const request = await context.client.query<RequestDataStructure<'eligibleShippingMethods', ShippingMethodQuote[]>>({
query: gql`${eligibleShippingMethods.query}`,
variables: eligibleShippingMethods.variables,
fetchPolicy: 'no-cache'
Expand Down
4 changes: 2 additions & 2 deletions packages/api-client/src/types/API.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { CustomQuery } from '@vue-storefront/core';
import { ApolloQueryResult } from 'apollo-client';
import { FetchResult } from 'apollo-link';
import { ActiveOrderResult, ApplyCouponCodeResult, CollectionList, Customer, Order, PaymentMethodQuote, Product, RemoveOrderItemsResult, SearchResponse, UpdateOrderItemsResult } from './GraphQL';
import { ActiveOrderResult, ApplyCouponCodeResult, CollectionList, Customer, Order, Product, RemoveOrderItemsResult, SearchResponse, ShippingMethodQuote, UpdateOrderItemsResult } from './GraphQL';
import { AddToCartParams, CartCouponParams, CollectionParams, ProductParams, RemoveFromCartParams, SearchParams, SetShippingMethodParams, UpdateAddressDetailsParams, UpdateCartParams } from './types';

export type QueryResponse<K extends string, V> = ApolloQueryResult<Record<K, V>>;
Expand All @@ -13,7 +13,7 @@ export type GetCategoryResponse = QueryResponse<'collections', CollectionList>;
export type GetFacetResponse = QueryResponse<'search', SearchResponse>;
export type GetCartResponse = QueryResponse<'activeOrder', Order>;
export type GetMeResponse = QueryResponse<'activeCustomer', Customer>;
export type GetShippingMethodsResponse = QueryResponse<'eligiblePaymentMethods', PaymentMethodQuote[]>;
export type GetShippingMethodsResponse = QueryResponse<'eligibleShippingMethods', ShippingMethodQuote[]>;
export type AddToCartResponse = MutationResponse<'addItemToOrder', UpdateOrderItemsResult>;
export type RemoveFromCartResponse = MutationResponse<'removeOrderLine', RemoveOrderItemsResult>;
export type UpdateCartQuantityResponse = MutationResponse<'adjustOrderLine', UpdateOrderItemsResult>;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,20 @@ import type { ShippingProvider, ShippingMethod } from '@vue-storefront/vendure-a
const params: UseShippingProviderParams<ShippingProvider, ShippingMethod> = {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
load: async (context: Context, { customQuery }) => {
console.log('Mocked: loadShippingProvider');
return {};
const response = await context.$vendure.api.getShippingMethods(customQuery);

return response?.data?.eligibleShippingMethods;
},

// eslint-disable-next-line @typescript-eslint/no-unused-vars
save: async (context: Context, { shippingMethod, customQuery }) => {
console.log('Mocked: saveShippingProvider');
return {};
}

set: async (context: Context) => {
// Set Cart value to a new returned from setShippingMethod
}
};

export const useShippingProvider = useShippingProviderFactory<ShippingProvider, ShippingMethod>(params);
30 changes: 20 additions & 10 deletions packages/theme/components/Checkout/CartPreview.vue
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,7 @@
/>
<SfProperty
:name="$t('Shipping')"
v-if="selectedShippingMethod && selectedShippingMethod.zoneRates"
:value="$n(getShippingMethodPrice(selectedShippingMethod, totals.total), 'currency')"
:value="$n(shippingCost, 'currency')"
class="sf-property--full-width sf-property--large property"
/>
<SfProperty
Expand Down Expand Up @@ -74,9 +73,9 @@ import {
SfInput,
SfCircleIcon
} from '@storefront-ui/vue';
import { computed, ref } from '@vue/composition-api';
import { useCart, useShippingProvider, cartGetters } from '@vue-storefront/vendure';
import { getShippingMethodPrice } from '~/helpers';
import { computed, ref, watch } from '@vue/composition-api';
import { useCart, cartGetters } from '@vue-storefront/vendure';
import { getCalculatedPrice } from '~/helpers';
export default {
name: 'CartPreview',
Expand All @@ -89,9 +88,14 @@ export default {
SfInput,
SfCircleIcon
},
setup () {
const { cart, removeItem, updateItemQty, applyCoupon } = useCart();
const { state } = useShippingProvider();
props: {
selectedShippingMethod: {
type: Object,
required: false,
}
},
setup (props) {
const { cart, removeItem, updateItemQty, applyCoupon, load } = useCart();
const listIsHidden = ref(false);
const promoCode = ref('');
Expand All @@ -101,6 +105,11 @@ export default {
const totalItems = computed(() => cartGetters.getTotalItems(cart.value));
const totals = computed(() => cartGetters.getTotals(cart.value));
const discounts = computed(() => cartGetters.getDiscounts(cart.value));
const shippingCost = computed(() => getCalculatedPrice(cart?.value?.shipping));
watch(() => props.selectedShippingMethod, async (newVal, oldVal) => {
await load();
});
return {
discounts,
Expand Down Expand Up @@ -133,9 +142,10 @@ export default {
}
],
selectedShippingMethod: computed(() => state.value && state.value.response && state.value.response.shippingMethod),
shippingCost,
hasSpecialPrice: computed(() => totals.value.special > 0 && totals.value.special < totals.value.subtotal),
getShippingMethodPrice
getCalculatedPrice,
cart
};
}
};
Expand Down
82 changes: 19 additions & 63 deletions packages/theme/components/Checkout/VsfShippingProvider.vue
Original file line number Diff line number Diff line change
Expand Up @@ -6,25 +6,22 @@
class="sf-heading--left sf-heading--no-underline title"
/>
<div class="form">
<SfLoader :loading="loading">
<div v-if="error.loadMethods">
{{ $t('There was some error while trying to fetch shipping methods. We are sorry, please try with different shipping details or later.') }}
</div>
<div v-else-if="errorShippingProvider.save">
<SfLoader :loading="loadingShippingProvider">
<div v-if="errorShippingProvider.save">
{{ $t('There was some error while trying to select this shipping method. We are sorry, please try with different shipping method or later.') }}
</div>
<div v-else-if="!shippingMethods.length">
<div v-else-if="!hasShippingMethods">
{{ $t('There are no shipping methods available for this country. We are sorry, please try with different country or later.') }}
</div>
</SfLoader>
<div class="form__radio-group">
<SfRadio
v-e2e="'shipping-method-label'"
v-for="method in shippingMethods"
v-for="method in state"
:key="method.id"
:label="method.name"
:value="method.id"
:selected="selectedShippingMethod && selectedShippingMethod.shippingMethod && selectedShippingMethod.shippingMethod.id"
:selected="selectedShippingMethod && selectedShippingMethod.id"
@input="selectShippingMethod(method)"
name="shippingMethod"
:description="method.localizedDescription"
Expand All @@ -33,7 +30,7 @@
<template #label="{ label }">
<div class="sf-radio__label shipping__label">
<div>{{ label }}</div>
<div v-if="method && method.zoneRates">{{ $n(getShippingMethodPrice(method, totals.total), 'currency') }}</div>
<div v-if="method && method.priceWithTax">{{ $n(getCalculatedPrice(method.priceWithTax), 'currency') }}</div>
</div>
</template>
<template #description="{ localizedDescription }">
Expand All @@ -58,7 +55,7 @@ import {
SfLoader
} from '@storefront-ui/vue';
import { ref, reactive, onMounted, computed } from '@vue/composition-api';
import { getShippingMethodPrice } from '~/helpers';
import { getCalculatedPrice } from '~/helpers';
import { useVSFContext } from '@vue-storefront/core';
export default {
Expand All @@ -76,7 +73,7 @@ export default {
},
afterLoad: {
type: Function,
default: shippingMethodsResponse => shippingMethodsResponse.shippingMethods
default: shippingMethodsResponse => shippingMethodsResponse
},
beforeSelect: {
type: Function,
Expand All @@ -101,87 +98,46 @@ export default {
default: ({ action, error }) => {}
}
},
setup (props) {
const loading = ref(false);
setup (props, { emit }) {
const shippingMethods = ref([]);
const { $ct } = useVSFContext();
const { $vendure } = useVSFContext();
const { cart } = useCart();
const {
state,
setState,
save,
load,
error: errorShippingProvider,
loading: loadingShippingProvider
} = useShippingProvider();
const selectedShippingMethod = computed(() => state.value && state.value.response);
const totals = computed(() => cartGetters.getTotals(cart.value));
const selectedShippingMethod = ref(null)
const error = reactive({
loadMethods: null
});
const loadMethods = async () => {
try {
error.loadMethods = null;
const shippingMethodsResponse = await $ct.api.getShippingMethods(cart.value.id);
return shippingMethodsResponse.data;
} catch (err) {
error.loadMethods = err;
await props.onError({
action: 'loadMethods',
error: error.loadMethods
});
}
};
const selectShippingMethod = async shippingMethod => {
if (loadingShippingProvider.value) {
return;
}
const interceptedShippingMethod = await props.beforeSelect(shippingMethod);
await save({ shippingMethod: interceptedShippingMethod });
if (errorShippingProvider.value.save) {
setState({
...(state.value ? state.value : {}),
_status: false
});
await props.onError({
action: 'selectShippingMethod',
error: errorShippingProvider.value.save
});
return;
}
await props.afterSelect(selectedShippingMethod.value);
setState({
...(state.value ? state.value : {}),
_status: true
});
await $vendure.api.setShippingMethod({ shippingMethodId: shippingMethod.id })
selectedShippingMethod.value = shippingMethod;
emit('shippingMethodSelected', shippingMethod);
};
const hasShippingMethods = computed(() => state?.value?.length);
onMounted(async () => {
loading.value = true;
await props.beforeLoad();
const shippingMethodsResponse = await loadMethods();
if (error.loadMethods) {
return;
}
await load();
shippingMethods.value = await props.afterLoad(shippingMethodsResponse);
loading.value = false;
});
return {
shippingMethods,
hasShippingMethods,
getCalculatedPrice,
selectedShippingMethod,
selectShippingMethod,
getShippingMethodPrice,
totals,
loading,
error,
errorShippingProvider,
loadingShippingProvider,
state
};
}
Expand Down
8 changes: 0 additions & 8 deletions packages/theme/helpers/checkout.ts

This file was deleted.

6 changes: 6 additions & 0 deletions packages/theme/helpers/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export const COUNTRIES = [
{ key: 'US', label: 'United States' },
{ key: 'UK', label: 'United Kingdom' },
{ key: 'IT', label: 'Italy' },
{ key: 'PL', label: 'Poland' }
];
2 changes: 1 addition & 1 deletion packages/theme/helpers/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
export * from './category';
export * from './checkout';
export * from './shipping-billing';
export * from './constants';
26 changes: 25 additions & 1 deletion packages/theme/helpers/shipping-billing.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { OrderAddress } from "~/../api-client/lib";
import { COUNTRIES } from "./constants";

interface AddressForm {
firstName: string,
Expand All @@ -19,4 +20,27 @@ export const mapAddressFormToOrderAddress = (addressForm: AddressForm): OrderAdd
postalCode: addressForm.postalCode,
countryCode: addressForm.country,
phoneNumber: addressForm.phone,
})
});

export const mapOrderAddressToAddressForm = (orderAddress: OrderAddress): AddressForm => {
const names = orderAddress?.fullName?.split(' ');
const address = orderAddress?.streetLine1?.split(' ');
const country = COUNTRIES.find(country => country.label === orderAddress?.country);
return {
firstName: names?.length ? names[0] : '',
lastName: names?.length ? names[1] : '',
streetName: address?.length ? address[0] : '',
apartment: address?.length ? address[1] : '',
city: orderAddress?.city,
state: '',
country: country?.key,
postalCode: orderAddress?.postalCode,
phone: orderAddress?.phoneNumber
}
}

export const getCalculatedPrice = (price: number): number => {
if (!price) return;

return price / 100;
}
Loading

0 comments on commit c03bf85

Please sign in to comment.