Closed andrzejewsky closed 3 years ago
Meeting nodes:
initialized
-> beforeLoad
loaded
-> afterLoad
methods:loaded
-> methods:beforeLoad
, methods:afterLoad
methods:changed
-> methods:selectedDetailsChanged
PaymentProvider
-> VsfPaymentProvider
VsfShippingProvider
-> for futureuse enums for event types
We will share const like:
const PaymentProviderEvents = {
BEFORE_PAY: 'payment:beforePay',
AFTER_PAY: 'payment:afterPay,
BEFORE_LOAD: 'methods:beforeLoad',
AFTER_LOAD: 'methods:afterLoad',
SELECTED: 'methods:selectedDetailsChanged',
CHANGED: 'methods:selectedDetailsChanged'
}
Then developer will just use
import { PaymentProviderEvents } from '...';
// ...
const onLoaded = () => {
context.emit(PaymentProviderEvents.LOADED)
}
I imagine component
will be mounted only after selection:
VsfShippingProviders.vue
<template>
<div>
<VsfShippingProvider
v-for="shippingProvider in shippingProviders"
>
<template #selected>
<component
:key="shippingProvider.id"
:is="shippingProviderToComponentName(shippingProvider)"
:data="shippingProvider"
:finished.sync="isShippingFinished"
:beforeLoad="config => ({...config, overwritenSmth: 12})"
@afterLoad="afterLoaded"
@method:selected="afterSelectedMethod"
@method:selectedDetailsChanged="afterSelectedDetailsChanged"
/>
</template>
</VsfShippingProvider>
<GoToBillingButton :disabled="!isShippingFinished" />
</div>
</template>
<script>
export default {
components: shippingProviderComponents,
setup () {
const isShippingFinished = ref(false);
const onChangeShippingProvider = () => {
isShippingFinished.value = false;
}
return {
isShippingFinished
}
}
}
</script>
Each shipping provider:
Hooks:
initialized
method. Otherwise, we won't be able to use what's handler returns.// shippingProviderToComponentName.ts
import { upsShippingProviderMapper } from 'ups';
// upsShippingProviderMapper = {
// componentName: 'UpsShippingProvider',
// checker: (shippingMethod: SHIPPING_METHOD) => Boolean
// }
import { dhlShippingProviderMapper } from 'dhl';
import { pdpShippingProviderMapper } from 'pdp';
import { inpostShippingProviderMapper } from 'inpost';
import { plainShippingProviderMapper } from '@vue-storefront/commercetools';
const providersMappers = [
upsShippingProviderMapper,
dhlShippingProviderMapper,
pdpShippingProviderMapper,
inpostShippingProviderMapper,
plainShippingProviderMapper
];
export const shippingProviderComponents = {
UpsShippingProviderComponent: () => import('ups/component'),
DhlShippingProviderComponent: () => import('dhl/component'),
PdpShippingProviderComponent: () => import('pdp/component'),
InpostShippingProviderComponent: () => import('inpost/component'),
PlainShippingProviderComponent: () => import('@vue-storefront/commercetools/component'),
};
export const shippingProviderToComponentName = (shippingProvider: SHIPPING_PROVIDER) => {
const providerMapper = providersMappers.find(providersMapper => providersMapper.checker(shippingProvider));
if(!providerMapper) {
throw new Error(`No matching component for ${shippingProvider.name} shipping method`);
}
return providerMapper.componentName;
}
Simple draft o shippingProvider
<template>
<ShippingProvider
:finished.sync="isShippingFinished"
:methods:beforeLoad="beforeLoad"
@methods:afterLoad="onAfterLoad"
@methods:selected="handleSelectMethod"
@methods:selectedDetailsChanged="handleChangeMethod"
@error="onError"
>
<template #default="{ name, price }">
Method {{ name }}, price: {{ price }}
</template>
</ShippingProvider>
</template>
methods:beforeLoad handler's signature: ()
methods:afterLoad handler's signature: ({ shippingMethods: SHIPPING_METHODS_RESPONSE })
methods:selected handler's signature: ({ shippingMethod: SHIPPING_METHOD })
This issue has been closed due to inactivity.
If you want to re-open the issue, please re-create the issue, and post newer information on this problem.
As some of the parts in VSF are really complicated and most of the logic belongs to the components, it's better to provide entire components with the ability for customizations instead of just composables.
Considering payment - we have a lot of variety of implementing such a thing, and each depends on the payment provider. Clearly, most of logic is hidden inside the components, while the composables are handling only a small piece of it.
To solve that issue we can introduce feature components, or agnostic (to some extend) components that are handling a implementation of this specific case, just based on the platform we integrate with.
We can assume that kind of component should take some input props (that comes from integration) and emits some predefined events that are mandatory to be consistent with a platform.
Example:
We have the following parts:
PaymentProvider
component is a feature components that always stick to the criteria (emited events and received prop)PaymentProvider
has also ability to extend the UI, the developer is able to inject into all of necessary scope of the UI such as single field, multiple field, specific field and also buttonPaymentProvider
is not fully agnostic: the slot params, input prop, event args etc. can be different and are depending on integationUtilities
initForm
,selectMethod
,loadMethods
,makePayment
etc.But based on integration the flow can be different which comes with different functions: